1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1999-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: Lightweight test server 24%%---------------------------------------------------------------------- 25%% 26 27-module(megaco_test_lib). 28 29%% -compile(export_all). 30 31-compile({no_auto_import, [error/3]}). 32 33-export([ 34 proxy_call/3, 35 log/4, 36 error/3, 37 38 sleep/1, 39 hours/1, minutes/1, seconds/1, 40 formated_timestamp/0, format_timestamp/1, 41 42 skip/3, 43 non_pc_tc_maybe_skip/4, 44 os_based_skip/1, 45 46 flush/0, 47 still_alive/1, 48 49 display_alloc_info/0, 50 display_system_info/1, display_system_info/2, display_system_info/3, 51 52 try_tc/6, 53 54 prepare_test_case/5, 55 56 proxy_start/1, proxy_start/2, 57 58 mk_nodes/1, 59 start_nodes/3, start_nodes/4, 60 start_node/3, start_node/4, 61 62 stop_nodes/3, 63 stop_node/3, 64 65 is_socket_backend/1, 66 inet_backend_opts/1, 67 explicit_inet_backend/0, test_inet_backends/0, 68 open/3, 69 listen/3, connect/3 70 71 ]). 72-export([init_per_suite/1, end_per_suite/1, 73 init_per_testcase/2, end_per_testcase/2]). 74 75-export([proxy_init/2]). 76 77-include("megaco_test_lib.hrl"). 78 79-record('REASON', {mod, line, desc}). 80 81 82%% ---------------------------------------------------------------- 83%% Proxy Call 84%% This is used when we need to assign a timeout to a call, but the 85%% call itself does not provide such an argument. 86%% 87%% This has nothing to to with the proxy_start and proxy_init 88%% functions below. 89 90proxy_call(F, Timeout, Default) 91 when is_function(F, 0) andalso 92 is_integer(Timeout) andalso (Timeout > 0) andalso 93 is_function(Default, 0) -> 94 {P, M} = erlang:spawn_monitor(fun() -> exit(F()) end), 95 receive 96 {'DOWN', M, process, P, Reply} -> 97 Reply 98 after Timeout -> 99 erlang:demonitor(M, [flush]), 100 exit(P, kill), 101 Default() 102 end; 103proxy_call(F, Timeout, Default) -> 104 proxy_call(F, Timeout, fun() -> Default end). 105 106 107%% ---------------------------------------------------------------- 108%% Time related function 109%% 110 111sleep(infinity) -> 112 receive 113 after infinity -> 114 ok 115 end; 116sleep(MSecs) -> 117 receive 118 after trunc(MSecs) -> 119 ok 120 end, 121 ok. 122 123 124hours(N) -> trunc(N * 1000 * 60 * 60). 125minutes(N) -> trunc(N * 1000 * 60). 126seconds(N) -> trunc(N * 1000). 127 128 129formated_timestamp() -> 130 format_timestamp(os:timestamp()). 131 132format_timestamp(TS) -> 133 megaco:format_timestamp(TS). 134 135 136%% ---------------------------------------------------------------- 137%% Conditional skip of testcases 138%% 139 140non_pc_tc_maybe_skip(Config, Condition, File, Line) 141 when is_list(Config) andalso is_function(Condition) -> 142 %% Check if we shall skip the skip 143 case os:getenv("TS_OS_BASED_SKIP") of 144 "false" -> 145 ok; 146 _ -> 147 case lists:keysearch(ts, 1, Config) of 148 {value, {ts, megaco}} -> 149 %% Always run the testcase if we are using our own 150 %% test-server... 151 ok; 152 _ -> 153 case (catch Condition()) of 154 true -> 155 skip(non_pc_testcase, File, Line); 156 _ -> 157 ok 158 end 159 end 160 end. 161 162 163%% The type and spec'ing is just to increase readability 164-type os_family() :: win32 | unix. 165-type os_name() :: atom(). 166-type os_version() :: string() | {non_neg_integer(), 167 non_neg_integer(), 168 non_neg_integer()}. 169-type os_skip_check() :: fun(() -> boolean()) | 170 fun((os_version()) -> boolean()). 171-type skippable() :: any | [os_family() | 172 {os_family(), os_name() | 173 [os_name() | {os_name(), 174 os_skip_check()}]}]. 175 176-spec os_based_skip(skippable()) -> boolean(). 177 178os_based_skip(any) -> 179 true; 180os_based_skip(Skippable) when is_list(Skippable) -> 181 os_base_skip(Skippable, os:type()); 182os_based_skip(_Crap) -> 183 false. 184 185os_base_skip(Skippable, {OsFam, OsName}) -> 186 os_base_skip(Skippable, OsFam, OsName); 187os_base_skip(Skippable, OsFam) -> 188 os_base_skip(Skippable, OsFam, undefined). 189 190os_base_skip(Skippable, OsFam, OsName) -> 191 %% Check if the entire family is to be skipped 192 %% Example: [win32, unix] 193 case lists:member(OsFam, Skippable) of 194 true -> 195 true; 196 false -> 197 %% Example: [{unix, freebsd}] | [{unix, [freebsd, darwin]}] 198 case lists:keysearch(OsFam, 1, Skippable) of 199 {value, {OsFam, OsName}} -> 200 true; 201 {value, {OsFam, Check}} when is_function(Check, 0) -> 202 Check(); 203 {value, {OsFam, Check}} when is_function(Check, 1) -> 204 Check(os:version()); 205 {value, {OsFam, OsNames}} when is_list(OsNames) -> 206 %% OsNames is a list of: 207 %% [atom()|{atom(), function/0 | function/1}] 208 case lists:member(OsName, OsNames) of 209 true -> 210 true; 211 false -> 212 os_based_skip_check(OsName, OsNames) 213 end; 214 _ -> 215 false 216 end 217 end. 218 219 220 221%% Performs a check via a provided fun with arity 0 or 1. 222%% The argument is the result of os:version(). 223os_based_skip_check(OsName, OsNames) -> 224 case lists:keysearch(OsName, 1, OsNames) of 225 {value, {OsName, Check}} when is_function(Check, 0) -> 226 Check(); 227 {value, {OsName, Check}} when is_function(Check, 1) -> 228 Check(os:version()); 229 _ -> 230 false 231 end. 232 233 234 235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 236%% Evaluates a test case or test suite 237%% Returns a list of failing test cases: 238%% 239%% {Mod, Fun, ExpectedRes, ActualRes} 240%%---------------------------------------------------------------------- 241 242display_alloc_info() -> 243 io:format("Allocator memory information:~n", []), 244 AllocInfo = alloc_info(), 245 display_alloc_info(AllocInfo). 246 247display_alloc_info([]) -> 248 ok; 249display_alloc_info([{Alloc, Mem}|AllocInfo]) -> 250 io:format(" ~15w: ~10w~n", [Alloc, Mem]), 251 display_alloc_info(AllocInfo). 252 253alloc_info() -> 254 case erlang:system_info(allocator) of 255 {_Allocator, _Version, Features, _Settings} -> 256 alloc_info(Features); 257 _ -> 258 [] 259 end. 260 261alloc_info(Allocators) -> 262 Allocs = [temp_alloc, sl_alloc, std_alloc, ll_alloc, eheap_alloc, 263 ets_alloc, binary_alloc, driver_alloc], 264 alloc_info(Allocators, Allocs, []). 265 266alloc_info([], _, Acc) -> 267 lists:reverse(Acc); 268alloc_info([Allocator | Allocators], Allocs, Acc) -> 269 case lists:member(Allocator, Allocs) of 270 true -> 271 Instances0 = erlang:system_info({allocator, Allocator}), 272 Instances = 273 if 274 is_list(Instances0) -> 275 [Instance || Instance <- Instances0, 276 element(1, Instance) =:= instance]; 277 true -> 278 [] 279 end, 280 AllocatorMem = alloc_mem_info(Instances), 281 alloc_info(Allocators, Allocs, [{Allocator, AllocatorMem} | Acc]); 282 283 false -> 284 alloc_info(Allocators, Allocs, Acc) 285 end. 286 287alloc_mem_info(Instances) -> 288 alloc_mem_info(Instances, []). 289 290alloc_mem_info([], Acc) -> 291 lists:sum([Mem || {instance, _, Mem} <- Acc]); 292alloc_mem_info([{instance, N, Info}|Instances], Acc) -> 293 InstanceMemInfo = alloc_instance_mem_info(Info), 294 alloc_mem_info(Instances, [{instance, N, InstanceMemInfo} | Acc]). 295 296alloc_instance_mem_info(InstanceInfo) -> 297 MBCS = alloc_instance_mem_info(mbcs, InstanceInfo), 298 SBCS = alloc_instance_mem_info(sbcs, InstanceInfo), 299 MBCS + SBCS. 300 301alloc_instance_mem_info(Key, InstanceInfo) -> 302 case lists:keysearch(Key, 1, InstanceInfo) of 303 {value, {Key, Info}} -> 304 case lists:keysearch(blocks_size, 1, Info) of 305 {value, {blocks_size, Mem, _, _}} -> 306 Mem; 307 _ -> 308 0 309 end; 310 _ -> 311 0 312 end. 313 314 315display_system_info(WhenStr) -> 316 display_system_info(WhenStr, undefined, undefined). 317 318display_system_info(WhenStr, undefined, undefined) -> 319 display_system_info(WhenStr, ""); 320display_system_info(WhenStr, Mod, Func) -> 321 ModFuncStr = lists:flatten(io_lib:format(" ~w:~w", [Mod, Func])), 322 display_system_info(WhenStr, ModFuncStr). 323 324display_system_info(WhenStr, ModFuncStr) -> 325 Fun = fun(F) -> case (catch F()) of 326 {'EXIT', _} -> 327 undefined; 328 Res -> 329 Res 330 end 331 end, 332 ProcCount = Fun(fun() -> erlang:system_info(process_count) end), 333 ProcLimit = Fun(fun() -> erlang:system_info(process_limit) end), 334 ProcMemAlloc = Fun(fun() -> erlang:memory(processes) end), 335 ProcMemUsed = Fun(fun() -> erlang:memory(processes_used) end), 336 ProcMemBin = Fun(fun() -> erlang:memory(binary) end), 337 ProcMemTot = Fun(fun() -> erlang:memory(total) end), 338 %% error_logger:info_msg( 339 io:format("~n" 340 "~n*********************************************" 341 "~n" 342 "System info ~s~s => " 343 "~n Process count: ~w" 344 "~n Process limit: ~w" 345 "~n Process memory alloc: ~w" 346 "~n Process memory used: ~w" 347 "~n Memory for binaries: ~w" 348 "~n Memory total: ~w" 349 "~n" 350 "~n*********************************************" 351 "~n" 352 "~n", [WhenStr, ModFuncStr, 353 ProcCount, ProcLimit, ProcMemAlloc, ProcMemUsed, 354 ProcMemBin, ProcMemTot]), 355 ok. 356 357 358 359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 360%% Verify that the actual result of a test case matches the exected one 361%% Returns the actual result 362%% Stores the result in the process dictionary if mismatch 363 364error(Actual, Mod, Line) -> 365 global:send(megaco_global_logger, {failed, Mod, Line}), 366 log("<ERROR> Bad result: ~p~n", [Actual], Mod, Line), 367 Label = lists:concat([Mod, "(", Line, ") unexpected result"]), 368 megaco:report_event(60, Mod, Mod, Label, 369 [{line, Mod, Line}, {error, Actual}]), 370 case global:whereis_name(megaco_test_case_sup) of 371 undefined -> 372 ignore; 373 Pid -> 374 Fail = #'REASON'{mod = Mod, line = Line, desc = Actual}, 375 Pid ! {fail, self(), Fail} 376 end, 377 Actual. 378 379log(Format, Args, Mod, Line) -> 380 case global:whereis_name(megaco_global_logger) of 381 undefined -> 382 io:format(user, "~p~p(~p): " ++ Format, 383 [self(), Mod, Line] ++ Args); 384 Pid -> 385 io:format(Pid, "~p~p(~p): " ++ Format, 386 [self(), Mod, Line] ++ Args) 387 end. 388 389skip(Reason) -> 390 exit({skip, Reason}). 391 392skip(Actual, File, Line) -> 393 log("Skipping test case: ~p~n", [Actual], File, Line), 394 String = f("~p(~p): ~p~n", [File, Line, Actual]), 395 skip(String). 396 397fatal_skip(Actual, File, Line) -> 398 error(Actual, File, Line), 399 skip({fatal, Actual, File, Line}). 400 401 402 403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 404%% Flush the message queue and return its messages 405 406flush() -> 407 receive 408 Msg -> 409 [Msg | flush()] 410 after 1000 -> 411 [] 412 end. 413 414 415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 416%% Check if process is alive and kicking 417 418still_alive(Pid) -> 419 erlang:is_process_alive(Pid). 420 421 422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 423%% The proxy process 424 425proxy_start(ProxyId) -> 426 spawn_link(?MODULE, proxy_init, [ProxyId, self()]). 427 428proxy_start(Node, ProxyId) -> 429 spawn_link(Node, ?MODULE, proxy_init, [ProxyId, self()]). 430 431proxy_init(ProxyId, Controller) -> 432 process_flag(trap_exit, true), 433 IdStr = proxyid2string(ProxyId), 434 put(id, IdStr), 435 ?LOG("[~s] proxy started by ~p~n", [IdStr, Controller]), 436 proxy_loop(ProxyId, Controller). 437 438proxy_loop(OwnId, Controller) -> 439 receive 440 {'EXIT', Controller, Reason} -> 441 pprint("proxy_loop -> received exit from controller" 442 "~n Reason: ~p", [Reason]), 443 exit(Reason); 444 {stop, Controller, Reason} -> 445 p("proxy_loop -> received stop from controller" 446 "~n Reason: ~p" 447 "~n", [Reason]), 448 exit(Reason); 449 450 {apply, Fun} -> 451 pprint("proxy_loop -> received apply request"), 452 Res = Fun(), 453 pprint("proxy_loop -> apply result: " 454 "~n ~p", [Res]), 455 Controller ! {res, OwnId, Res}, 456 proxy_loop(OwnId, Controller); 457 OtherMsg -> 458 pprint("proxy_loop -> received unknown message: " 459 "~n ~p", [OtherMsg]), 460 Controller ! {msg, OwnId, OtherMsg}, 461 proxy_loop(OwnId, Controller) 462 end. 463 464proxyid2string(Id) when is_list(Id) -> 465 Id; 466proxyid2string(Id) when is_atom(Id) -> 467 atom_to_list(Id); 468proxyid2string(Id) -> 469 f("~p", [Id]). 470 471pprint(F) -> 472 pprint(F, []). 473 474pprint(F, A) -> 475 io:format("[~s] ~p ~s " ++ F ++ "~n", 476 [get(id), self(), formated_timestamp() | A]). 477 478 479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 480%% Test server callbacks 481 482init_per_suite(Config) -> 483 484 p("megaco environment: " 485 "~n (megaco) app: ~p" 486 "~n (all) init: ~p" 487 "~n (megaco) init: ~p", 488 [application:get_all_env(megaco), 489 init:get_arguments(), 490 case init:get_argument(megaco) of 491 {ok, Args} -> Args; 492 error -> undefined 493 end]), 494 495 ct:timetrap(minutes(3)), 496 497 try analyze_and_print_host_info() of 498 {Factor, HostInfo} when is_integer(Factor) -> 499 try maybe_skip(HostInfo) of 500 true -> 501 {skip, "Unstable host and/or os (or combo thererof)"}; 502 false -> 503 maybe_start_global_sys_monitor(Config), 504 [{megaco_factor, Factor} | Config] 505 catch 506 throw:{skip, _} = SKIP -> 507 SKIP 508 end 509 catch 510 throw:{skip, _} = SKIP -> 511 SKIP 512 end. 513 514maybe_skip(_HostInfo) -> 515 516 %% We have some crap machines that causes random test case failures 517 %% for no obvious reason. So, attempt to identify those without actually 518 %% checking for the host name... 519 520 LinuxVersionVerify = 521 fun(V) when (V > {3,6,11}) -> 522 false; % OK - No skip 523 (V) when (V =:= {3,6,11}) -> 524 case string:trim(os:cmd("cat /etc/issue")) of 525 "Fedora release 16 " ++ _ -> % Stone age Fedora => Skip 526 true; 527 _ -> 528 false 529 end; 530 (V) when (V =:= {3,4,20}) -> 531 case string:trim(os:cmd("cat /etc/issue")) of 532 "Wind River Linux 5.0.1.0" ++ _ -> % *Old* Wind River => skip 533 true; 534 _ -> 535 false 536 end; 537 (V) when (V =:= {2,6,32}) -> 538 case string:trim(os:cmd("cat /etc/issue")) of 539 "Debian GNU/Linux 6.0 " ++ _ -> % Stone age Debian => Skip 540 true; 541 _ -> 542 false 543 end; 544 (V) when (V =:= {2,6,16}) -> 545 case string:trim(os:cmd("cat /etc/issue")) of 546 %% Stone age SLES => Skip 547 %% We have atleast one VM that has this version, 548 %% and it causes randome timeout glitches... 549 "Welcome to SUSE Linux Enterprise Server 10 SP1 " ++ _ -> 550 true; 551 _ -> 552 false 553 end; 554 (V) when (V =:= {2,6,10}) -> 555 case string:trim(os:cmd("cat /etc/issue")) of 556 "MontaVista" ++ _ -> % Stone age MontaVista => Skip 557 %% The real problem is that the machine is *very* slow 558 true; 559 _ -> 560 false 561 end; 562 (V) when (V > {2,6,24}) -> 563 false; % OK - No skip 564 (_) -> 565 %% We are specifically checking for 566 %% a *really* old gento... 567 case string:find(string:strip(os:cmd("uname -a")), "gentoo") of 568 nomatch -> 569 false; 570 _ -> % Stone age gentoo => Skip 571 true 572 end 573 end, 574 DarwinVersionVerify = 575 fun(V) when (V > {9, 8, 0}) -> 576 %% This version is OK: No Skip 577 false; 578 (_V) -> 579 %% This version is *not* ok: Skip 580 true 581 end, 582 SkipWindowsOnVirtual = 583 %% fun() -> 584 %% SysMan = win_sys_info_lookup(system_manufacturer, HostInfo), 585 %% case string:to_lower(SysMan) of 586 %% "vmware" ++ _ -> 587 %% true; 588 %% _ -> 589 %% false 590 %% end 591 %% end, 592 fun() -> 593 %% The host has been replaced and the VM has been reinstalled 594 %% so for now we give it a chance... 595 false 596 end, 597 COND = [ 598 {unix, [{linux, LinuxVersionVerify}, 599 {darwin, DarwinVersionVerify}]}, 600 {win32, SkipWindowsOnVirtual} 601 ], 602 os_based_skip(COND). 603 604%% We start the global system monitor unless explicitly disabled 605maybe_start_global_sys_monitor(Config) -> 606 case lists:keysearch(sysmon, 1, Config) of 607 {value, {sysmon, false}} -> 608 ok; 609 _ -> 610 megaco_test_global_sys_monitor:start() 611 end. 612 613end_per_suite(Config) when is_list(Config) -> 614 615 case lists:keysearch(sysmon, 1, Config) of 616 {value, {sysmon, false}} -> 617 ok; 618 _ -> 619 megaco_test_global_sys_monitor:stop() 620 end, 621 622 Config. 623 624 625init_per_testcase(_Case, Config) -> 626 Pid = group_leader(), 627 Name = megaco_global_logger, 628 case global:whereis_name(Name) of 629 undefined -> 630 global:register_name(megaco_global_logger, Pid); 631 Pid -> 632 io:format("~w:init_per_testcase -> " 633 "already registered to ~p~n", [?MODULE, Pid]), 634 ok; 635 OtherPid when is_pid(OtherPid) -> 636 io:format("~w:init_per_testcase -> " 637 "already registered to other ~p (~p)~n", 638 [?MODULE, OtherPid, Pid]), 639 exit({already_registered, {megaco_global_logger, OtherPid, Pid}}) 640 end, 641 set_kill_timer(Config). 642 643end_per_testcase(_Case, Config) -> 644 Name = megaco_global_logger, 645 case global:whereis_name(Name) of 646 undefined -> 647 io:format("~w:end_per_testcase -> already un-registered~n", 648 [?MODULE]), 649 ok; 650 Pid when is_pid(Pid) -> 651 global:unregister_name(megaco_global_logger), 652 ok 653 end, 654 reset_kill_timer(Config). 655 656 657%% This function prints various host info, which might be usefull 658%% when analyzing the test suite (results). 659%% It also returns a "factor" that can be used when deciding 660%% the load for some test cases. Such as run time or number of 661%% iteraions. This only works for some OSes. 662%% 663analyze_and_print_host_info() -> 664 {OsFam, OsName} = os:type(), 665 Version = 666 case os:version() of 667 {Maj, Min, Rel} -> 668 f("~w.~w.~w", [Maj, Min, Rel]); 669 VStr -> 670 VStr 671 end, 672 case {OsFam, OsName} of 673 {unix, linux} -> 674 analyze_and_print_linux_host_info(Version); 675 {unix, openbsd} -> 676 analyze_and_print_openbsd_host_info(Version); 677 {unix, freebsd} -> 678 analyze_and_print_freebsd_host_info(Version); 679 {unix, netbsd} -> 680 analyze_and_print_netbsd_host_info(Version); 681 {unix, darwin} -> 682 analyze_and_print_darwin_host_info(Version); 683 {unix, sunos} -> 684 analyze_and_print_solaris_host_info(Version); 685 {win32, nt} -> 686 analyze_and_print_win_host_info(Version); 687 _ -> 688 io:format("OS Family: ~p" 689 "~n OS Type: ~p" 690 "~n Version: ~p" 691 "~n Num Online Schedulers: ~s" 692 "~n", [OsFam, OsName, Version, str_num_schedulers()]), 693 {num_schedulers_to_factor(), []} 694 end. 695 696str_num_schedulers() -> 697 try erlang:system_info(schedulers_online) of 698 N -> f("~w", [N]) 699 catch 700 _:_:_ -> "-" 701 end. 702 703num_schedulers_to_factor() -> 704 try erlang:system_info(schedulers_online) of 705 1 -> 706 10; 707 2 -> 708 5; 709 N when (N =< 6) -> 710 2; 711 _ -> 712 1 713 catch 714 _:_:_ -> 715 10 716 end. 717 718 719 720linux_which_distro(Version) -> 721 case file:read_file_info("/etc/issue") of 722 {ok, _} -> 723 case [string:trim(S) || 724 S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of 725 [DistroStr|_] -> 726 io:format("Linux: ~s" 727 "~n ~s" 728 "~n", 729 [Version, DistroStr]), 730 case DistroStr of 731 "Wind River Linux" ++ _ -> 732 wind_river; 733 "MontaVista" ++ _ -> 734 montavista; 735 "Yellow Dog" ++ _ -> 736 yellow_dog; 737 _ -> 738 other 739 end; 740 X -> 741 io:format("Linux: ~s" 742 "~n ~p" 743 "~n", 744 [Version, X]), 745 other 746 end; 747 _ -> 748 io:format("Linux: ~s" 749 "~n", [Version]), 750 other 751 end. 752 753 754analyze_and_print_linux_host_info(Version) -> 755 Distro = linux_which_distro(Version), 756 Factor = 757 case (catch linux_which_cpuinfo(Distro)) of 758 {ok, {CPU, BogoMIPS}} -> 759 io:format("CPU: " 760 "~n Model: ~s" 761 "~n BogoMIPS: ~w" 762 "~n Num Online Schedulers: ~s" 763 "~n", [CPU, BogoMIPS, str_num_schedulers()]), 764 if 765 (BogoMIPS > 20000) -> 766 1; 767 (BogoMIPS > 10000) -> 768 2; 769 (BogoMIPS > 5000) -> 770 3; 771 (BogoMIPS > 2000) -> 772 5; 773 (BogoMIPS > 1000) -> 774 8; 775 true -> 776 10 777 end; 778 {ok, CPU} -> 779 io:format("CPU: " 780 "~n Model: ~s" 781 "~n Num Online Schedulers: ~s" 782 "~n", [CPU, str_num_schedulers()]), 783 num_schedulers_to_factor(); 784 _ -> 785 5 786 end, 787 %% Check if we need to adjust the factor because of the memory 788 try linux_which_meminfo() of 789 AddFactor -> 790 {Factor + AddFactor, []} 791 catch 792 _:_:_ -> 793 {Factor, []} 794 end. 795 796 797linux_cpuinfo_lookup(Key) when is_list(Key) -> 798 linux_info_lookup(Key, "/proc/cpuinfo"). 799 800linux_cpuinfo_cpu() -> 801 case linux_cpuinfo_lookup("cpu") of 802 [Model] -> 803 Model; 804 _ -> 805 "-" 806 end. 807 808linux_cpuinfo_motherboard() -> 809 case linux_cpuinfo_lookup("motherboard") of 810 [MB] -> 811 MB; 812 _ -> 813 "-" 814 end. 815 816linux_cpuinfo_bogomips() -> 817 case linux_cpuinfo_lookup("bogomips") of 818 BMips when is_list(BMips) -> 819 try lists:sum([bogomips_to_int(BM) || BM <- BMips]) 820 catch 821 _:_:_ -> 822 "-" 823 end; 824 _ -> 825 "-" 826 end. 827 828linux_cpuinfo_total_bogomips() -> 829 case linux_cpuinfo_lookup("total bogomips") of 830 [TBM] -> 831 try bogomips_to_int(TBM) 832 catch 833 _:_:_ -> 834 "-" 835 end; 836 _ -> 837 "-" 838 end. 839 840bogomips_to_int(BM) -> 841 try list_to_float(BM) of 842 F -> 843 floor(F) 844 catch 845 _:_:_ -> 846 try list_to_integer(BM) of 847 I -> 848 I 849 catch 850 _:_:_ -> 851 throw(noinfo) 852 end 853 end. 854 855linux_cpuinfo_model() -> 856 case linux_cpuinfo_lookup("model") of 857 [M] -> 858 M; 859 _ -> 860 "-" 861 end. 862 863linux_cpuinfo_platform() -> 864 case linux_cpuinfo_lookup("platform") of 865 [P] -> 866 P; 867 _ -> 868 "-" 869 end. 870 871linux_cpuinfo_model_name() -> 872 case linux_cpuinfo_lookup("model name") of 873 [P|_] -> 874 P; 875 _X -> 876 "-" 877 end. 878 879linux_cpuinfo_processor() -> 880 case linux_cpuinfo_lookup("Processor") of 881 [P] -> 882 P; 883 _ -> 884 "-" 885 end. 886 887linux_which_cpuinfo(montavista) -> 888 CPU = 889 case linux_cpuinfo_cpu() of 890 "-" -> 891 throw(noinfo); 892 Model -> 893 case linux_cpuinfo_motherboard() of 894 "-" -> 895 Model; 896 MB -> 897 Model ++ " (" ++ MB ++ ")" 898 end 899 end, 900 case linux_cpuinfo_bogomips() of 901 "-" -> 902 {ok, CPU}; 903 BMips -> 904 {ok, {CPU, BMips}} 905 end; 906 907linux_which_cpuinfo(yellow_dog) -> 908 CPU = 909 case linux_cpuinfo_cpu() of 910 "-" -> 911 throw(noinfo); 912 Model -> 913 case linux_cpuinfo_motherboard() of 914 "-" -> 915 Model; 916 MB -> 917 Model ++ " (" ++ MB ++ ")" 918 end 919 end, 920 {ok, CPU}; 921 922linux_which_cpuinfo(wind_river) -> 923 CPU = 924 case linux_cpuinfo_model() of 925 "-" -> 926 throw(noinfo); 927 Model -> 928 case linux_cpuinfo_platform() of 929 "-" -> 930 Model; 931 Platform -> 932 Model ++ " (" ++ Platform ++ ")" 933 end 934 end, 935 case linux_cpuinfo_total_bogomips() of 936 "-" -> 937 {ok, CPU}; 938 BMips -> 939 {ok, {CPU, BMips}} 940 end; 941 942linux_which_cpuinfo(other) -> 943 %% Check for x86 (Intel or AMD) 944 CPU = 945 case linux_cpuinfo_model_name() of 946 "-" -> 947 %% ARM (at least some distros...) 948 case linux_cpuinfo_processor() of 949 "-" -> 950 %% Ok, we give up 951 throw(noinfo); 952 Proc -> 953 Proc 954 end; 955 ModelName -> 956 ModelName 957 end, 958 case linux_cpuinfo_bogomips() of 959 "-" -> 960 {ok, CPU}; 961 BMips -> 962 {ok, {CPU, BMips}} 963 end. 964 965linux_meminfo_lookup(Key) when is_list(Key) -> 966 linux_info_lookup(Key, "/proc/meminfo"). 967 968linux_meminfo_memtotal() -> 969 case linux_meminfo_lookup("MemTotal") of 970 [X] -> 971 X; 972 _ -> 973 "-" 974 end. 975 976%% We *add* the value this return to the Factor. 977linux_which_meminfo() -> 978 case linux_meminfo_memtotal() of 979 "-" -> 980 0; 981 MemTotal -> 982 io:format("Memory:" 983 "~n ~s" 984 "~n", [MemTotal]), 985 case string:tokens(MemTotal, [$ ]) of 986 [MemSzStr, MemUnit] -> 987 MemSz2 = list_to_integer(MemSzStr), 988 MemSz3 = 989 case string:to_lower(MemUnit) of 990 "kb" -> 991 MemSz2; 992 "mb" -> 993 MemSz2*1024; 994 "gb" -> 995 MemSz2*1024*1024; 996 _ -> 997 throw(noinfo) 998 end, 999 if 1000 (MemSz3 >= 8388608) -> 1001 0; 1002 (MemSz3 >= 4194304) -> 1003 1; 1004 (MemSz3 >= 2097152) -> 1005 3; 1006 true -> 1007 5 1008 end; 1009 _X -> 1010 0 1011 end 1012 end. 1013 1014 1015%% Just to be clear: This is ***not*** scientific... 1016analyze_and_print_openbsd_host_info(Version) -> 1017 io:format("OpenBSD:" 1018 "~n Version: ~p" 1019 "~n", [Version]), 1020 Extract = 1021 fun(Key) -> 1022 string:tokens(string:trim(os:cmd("sysctl " ++ Key)), [$=]) 1023 end, 1024 try 1025 begin 1026 CPU = 1027 case Extract("hw.model") of 1028 ["hw.model", Model] -> 1029 string:trim(Model); 1030 _ -> 1031 "-" 1032 end, 1033 CPUSpeed = 1034 case Extract("hw.cpuspeed") of 1035 ["hw.cpuspeed", Speed] -> 1036 list_to_integer(Speed); 1037 _ -> 1038 -1 1039 end, 1040 NCPU = 1041 case Extract("hw.ncpufound") of 1042 ["hw.ncpufound", N] -> 1043 list_to_integer(N); 1044 _ -> 1045 -1 1046 end, 1047 Memory = 1048 case Extract("hw.physmem") of 1049 ["hw.physmem", PhysMem] -> 1050 list_to_integer(PhysMem) div 1024; 1051 _ -> 1052 -1 1053 end, 1054 io:format("CPU:" 1055 "~n Model: ~s" 1056 "~n Speed: ~w" 1057 "~n N: ~w" 1058 "~nMemory:" 1059 "~n ~w KB" 1060 "~n", [CPU, CPUSpeed, NCPU, Memory]), 1061 CPUFactor = 1062 if 1063 (CPUSpeed =:= -1) -> 1064 1; 1065 (CPUSpeed >= 2000) -> 1066 if 1067 (NCPU >= 4) -> 1068 1; 1069 (NCPU >= 2) -> 1070 2; 1071 true -> 1072 3 1073 end; 1074 true -> 1075 if 1076 (NCPU >= 4) -> 1077 2; 1078 (NCPU >= 2) -> 1079 3; 1080 true -> 1081 4 1082 end 1083 end, 1084 MemAddFactor = 1085 if 1086 (Memory =:= -1) -> 1087 0; 1088 (Memory >= 8388608) -> 1089 0; 1090 (Memory >= 4194304) -> 1091 1; 1092 (Memory >= 2097152) -> 1093 2; 1094 true -> 1095 3 1096 end, 1097 {CPUFactor + MemAddFactor, []} 1098 end 1099 catch 1100 _:_:_ -> 1101 {5, []} 1102 end. 1103 1104 1105analyze_and_print_freebsd_host_info(Version) -> 1106 io:format("FreeBSD:" 1107 "~n Version: ~p" 1108 "~n", [Version]), 1109 %% This test require that the program 'sysctl' is in the path. 1110 %% First test with 'which sysctl', if that does not work 1111 %% try with 'which /sbin/sysctl'. If that does not work either, 1112 %% we skip the test... 1113 try 1114 begin 1115 SysCtl = 1116 case string:trim(os:cmd("which sysctl")) of 1117 [] -> 1118 case string:trim(os:cmd("which /sbin/sysctl")) of 1119 [] -> 1120 throw(sysctl); 1121 SC2 -> 1122 SC2 1123 end; 1124 SC1 -> 1125 SC1 1126 end, 1127 Extract = 1128 fun(Key) -> 1129 string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)), 1130 [$:]) 1131 end, 1132 CPU = analyze_freebsd_cpu(Extract), 1133 CPUSpeed = analyze_freebsd_cpu_speed(Extract), 1134 NCPU = analyze_freebsd_ncpu(Extract), 1135 Memory = analyze_freebsd_memory(Extract), 1136 io:format("CPU:" 1137 "~n Model: ~s" 1138 "~n Speed: ~w" 1139 "~n N: ~w" 1140 "~n Num Schedulers: ~w" 1141 "~nMemory:" 1142 "~n ~w KB" 1143 "~n", 1144 [CPU, CPUSpeed, NCPU, 1145 erlang:system_info(schedulers), Memory]), 1146 CPUFactor = 1147 if 1148 (CPUSpeed =:= -1) -> 1149 1; 1150 (CPUSpeed >= 2000) -> 1151 if 1152 (NCPU >= 4) -> 1153 1; 1154 (NCPU >= 2) -> 1155 2; 1156 true -> 1157 3 1158 end; 1159 true -> 1160 if 1161 (NCPU =:= -1) -> 1162 1; 1163 (NCPU >= 4) -> 1164 2; 1165 (NCPU >= 2) -> 1166 3; 1167 true -> 1168 4 1169 end 1170 end, 1171 MemAddFactor = 1172 if 1173 (Memory =:= -1) -> 1174 0; 1175 (Memory >= 8388608) -> 1176 0; 1177 (Memory >= 4194304) -> 1178 1; 1179 (Memory >= 2097152) -> 1180 2; 1181 true -> 1182 3 1183 end, 1184 {CPUFactor + MemAddFactor, []} 1185 end 1186 catch 1187 _:_:_ -> 1188 io:format("CPU:" 1189 "~n Num Schedulers: ~w" 1190 "~n", [erlang:system_info(schedulers)]), 1191 Factor = case erlang:system_info(schedulers) of 1192 1 -> 1193 10; 1194 2 -> 1195 5; 1196 _ -> 1197 2 1198 end, 1199 {Factor, []} 1200 end. 1201 1202analyze_freebsd_cpu(Extract) -> 1203 analyze_freebsd_item(Extract, "hw.model", fun(X) -> X end, "-"). 1204 1205analyze_freebsd_cpu_speed(Extract) -> 1206 analyze_freebsd_item(Extract, 1207 "hw.clockrate", 1208 fun(X) -> list_to_integer(X) end, 1209 -1). 1210 1211analyze_freebsd_ncpu(Extract) -> 1212 analyze_freebsd_item(Extract, 1213 "hw.ncpu", 1214 fun(X) -> list_to_integer(X) end, 1215 -1). 1216 1217analyze_freebsd_memory(Extract) -> 1218 analyze_freebsd_item(Extract, 1219 "hw.physmem", 1220 fun(X) -> list_to_integer(X) div 1024 end, 1221 -1). 1222 1223analyze_freebsd_item(Extract, Key, Process, Default) -> 1224 try 1225 begin 1226 case Extract(Key) of 1227 [Key, Model] -> 1228 Process(string:trim(Model)); 1229 _ -> 1230 Default 1231 end 1232 end 1233 catch 1234 _:_:_ -> 1235 Default 1236 end. 1237 1238 1239analyze_and_print_netbsd_host_info(Version) -> 1240 io:format("NetBSD:" 1241 "~n Version: ~p" 1242 "~n", [Version]), 1243 %% This test require that the program 'sysctl' is in the path. 1244 %% First test with 'which sysctl', if that does not work 1245 %% try with 'which /sbin/sysctl'. If that does not work either, 1246 %% we skip the test... 1247 try 1248 begin 1249 SysCtl = 1250 case string:trim(os:cmd("which sysctl")) of 1251 [] -> 1252 case string:trim(os:cmd("which /sbin/sysctl")) of 1253 [] -> 1254 throw(sysctl); 1255 SC2 -> 1256 SC2 1257 end; 1258 SC1 -> 1259 SC1 1260 end, 1261 Extract = 1262 fun(Key) -> 1263 [string:trim(S) || 1264 S <- 1265 string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)), 1266 [$=])] 1267 end, 1268 CPU = analyze_netbsd_cpu(Extract), 1269 Machine = analyze_netbsd_machine(Extract), 1270 Arch = analyze_netbsd_machine_arch(Extract), 1271 CPUSpeed = analyze_netbsd_cpu_speed(Extract), 1272 NCPU = analyze_netbsd_ncpu(Extract), 1273 Memory = analyze_netbsd_memory(Extract), 1274 io:format("CPU:" 1275 "~n Model: ~s (~s, ~s)" 1276 "~n Speed: ~w MHz" 1277 "~n N: ~w" 1278 "~n Num Schedulers: ~w" 1279 "~nMemory:" 1280 "~n ~w KB" 1281 "~n", 1282 [CPU, Machine, Arch, CPUSpeed, NCPU, 1283 erlang:system_info(schedulers), Memory]), 1284 CPUFactor = 1285 if 1286 (CPUSpeed =:= -1) -> 1287 1; 1288 (CPUSpeed >= 2000) -> 1289 if 1290 (NCPU >= 4) -> 1291 1; 1292 (NCPU >= 2) -> 1293 2; 1294 true -> 1295 3 1296 end; 1297 true -> 1298 if 1299 (NCPU =:= -1) -> 1300 1; 1301 (NCPU >= 4) -> 1302 2; 1303 (NCPU >= 2) -> 1304 3; 1305 true -> 1306 4 1307 end 1308 end, 1309 MemAddFactor = 1310 if 1311 (Memory =:= -1) -> 1312 0; 1313 (Memory >= 8388608) -> 1314 0; 1315 (Memory >= 4194304) -> 1316 1; 1317 (Memory >= 2097152) -> 1318 2; 1319 true -> 1320 3 1321 end, 1322 {CPUFactor + MemAddFactor, []} 1323 end 1324 catch 1325 _:_:_ -> 1326 io:format("CPU:" 1327 "~n Num Schedulers: ~w" 1328 "~n", [erlang:system_info(schedulers)]), 1329 Factor = case erlang:system_info(schedulers) of 1330 1 -> 1331 10; 1332 2 -> 1333 5; 1334 _ -> 1335 2 1336 end, 1337 {Factor, []} 1338 end. 1339 1340analyze_netbsd_cpu(Extract) -> 1341 analyze_netbsd_item(Extract, "hw.model", fun(X) -> X end, "-"). 1342 1343analyze_netbsd_machine(Extract) -> 1344 analyze_netbsd_item(Extract, "hw.machine", fun(X) -> X end, "-"). 1345 1346analyze_netbsd_machine_arch(Extract) -> 1347 analyze_netbsd_item(Extract, "hw.machine_arch", fun(X) -> X end, "-"). 1348 1349analyze_netbsd_cpu_speed(Extract) -> 1350 analyze_netbsd_item(Extract, "machdep.dmi.processor-frequency", 1351 fun(X) -> case string:tokens(X, [$\ ]) of 1352 [MHz, "MHz"] -> 1353 list_to_integer(MHz); 1354 _ -> 1355 -1 1356 end 1357 end, "-"). 1358 1359analyze_netbsd_ncpu(Extract) -> 1360 analyze_netbsd_item(Extract, 1361 "hw.ncpu", 1362 fun(X) -> list_to_integer(X) end, 1363 -1). 1364 1365analyze_netbsd_memory(Extract) -> 1366 analyze_netbsd_item(Extract, 1367 "hw.physmem64", 1368 fun(X) -> list_to_integer(X) div 1024 end, 1369 -1). 1370 1371analyze_netbsd_item(Extract, Key, Process, Default) -> 1372 analyze_freebsd_item(Extract, Key, Process, Default). 1373 1374 1375 1376%% Model Identifier: Macmini7,1 1377%% Processor Name: Intel Core i5 1378%% Processor Speed: 2,6 GHz 1379%% Number of Processors: 1 1380%% Total Number of Cores: 2 1381%% L2 Cache (per Core): 256 KB 1382%% L3 Cache: 3 MB 1383%% Hyper-Threading Technology: Enabled 1384%% Memory: 16 GB 1385 1386analyze_and_print_darwin_host_info(Version) -> 1387 %% This stuff is for macOS. 1388 %% If we ever tested on a pure darwin machine, 1389 %% we need to find some other way to find some info... 1390 %% Also, I suppose its possible that we for some other 1391 %% reason *fail* to get the info... 1392 case analyze_darwin_software_info() of 1393 [] -> 1394 io:format("Darwin:" 1395 "~n Version: ~s" 1396 "~n Num Online Schedulers: ~s" 1397 "~n", [Version, str_num_schedulers()]), 1398 {num_schedulers_to_factor(), []}; 1399 SwInfo when is_list(SwInfo) -> 1400 SystemVersion = analyze_darwin_sw_system_version(SwInfo), 1401 KernelVersion = analyze_darwin_sw_kernel_version(SwInfo), 1402 HwInfo = analyze_darwin_hardware_info(), 1403 ModelName = analyze_darwin_hw_model_name(HwInfo), 1404 ModelId = analyze_darwin_hw_model_identifier(HwInfo), 1405 ProcName = analyze_darwin_hw_processor_name(HwInfo), 1406 ProcSpeed = analyze_darwin_hw_processor_speed(HwInfo), 1407 NumProc = analyze_darwin_hw_number_of_processors(HwInfo), 1408 NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), 1409 Memory = analyze_darwin_hw_memory(HwInfo), 1410 io:format("Darwin:" 1411 "~n System Version: ~s" 1412 "~n Kernel Version: ~s" 1413 "~n Model: ~s (~s)" 1414 "~n Processor: ~s (~s, ~s, ~s)" 1415 "~n Memory: ~s" 1416 "~n Num Online Schedulers: ~s" 1417 "~n", [SystemVersion, KernelVersion, 1418 ModelName, ModelId, 1419 ProcName, ProcSpeed, NumProc, NumCores, 1420 Memory, 1421 str_num_schedulers()]), 1422 CPUFactor = analyze_darwin_cpu_to_factor(ProcName, 1423 ProcSpeed, 1424 NumProc, 1425 NumCores), 1426 MemFactor = analyze_darwin_memory_to_factor(Memory), 1427 if (MemFactor =:= 1) -> 1428 {CPUFactor, []}; 1429 true -> 1430 {CPUFactor + MemFactor, []} 1431 end 1432 end. 1433 1434analyze_darwin_sw_system_version(SwInfo) -> 1435 proplists:get_value("system version", SwInfo, "-"). 1436 1437analyze_darwin_sw_kernel_version(SwInfo) -> 1438 proplists:get_value("kernel version", SwInfo, "-"). 1439 1440analyze_darwin_software_info() -> 1441 analyze_darwin_system_profiler("SPSoftwareDataType"). 1442 1443analyze_darwin_hw_model_name(HwInfo) -> 1444 proplists:get_value("model name", HwInfo, "-"). 1445 1446analyze_darwin_hw_model_identifier(HwInfo) -> 1447 proplists:get_value("model identifier", HwInfo, "-"). 1448 1449analyze_darwin_hw_processor_name(HwInfo) -> 1450 proplists:get_value("processor name", HwInfo, "-"). 1451 1452analyze_darwin_hw_processor_speed(HwInfo) -> 1453 proplists:get_value("processor speed", HwInfo, "-"). 1454 1455analyze_darwin_hw_number_of_processors(HwInfo) -> 1456 proplists:get_value("number of processors", HwInfo, "-"). 1457 1458analyze_darwin_hw_total_number_of_cores(HwInfo) -> 1459 proplists:get_value("total number of cores", HwInfo, "-"). 1460 1461analyze_darwin_hw_memory(HwInfo) -> 1462 proplists:get_value("memory", HwInfo, "-"). 1463 1464analyze_darwin_hardware_info() -> 1465 analyze_darwin_system_profiler("SPHardwareDataType"). 1466 1467%% This basically has the structure: "Key: Value" 1468%% But could also be (for example): 1469%% "Something:" (which we ignore) 1470%% "Key: Value1:Value2" 1471analyze_darwin_system_profiler(DataType) -> 1472 %% First, make sure the program actually exist: 1473 case os:cmd("which system_profiler") of 1474 [] -> 1475 []; 1476 _ -> 1477 D0 = os:cmd("system_profiler " ++ DataType), 1478 D1 = string:tokens(D0, [$\n]), 1479 D2 = [string:trim(S1) || S1 <- D1], 1480 D3 = [string:tokens(S2, [$:]) || S2 <- D2], 1481 analyze_darwin_system_profiler2(D3) 1482 end. 1483 1484analyze_darwin_system_profiler2(L) -> 1485 analyze_darwin_system_profiler2(L, []). 1486 1487analyze_darwin_system_profiler2([], Acc) -> 1488 [{string:to_lower(K), V} || {K, V} <- lists:reverse(Acc)]; 1489analyze_darwin_system_profiler2([[_]|T], Acc) -> 1490 analyze_darwin_system_profiler2(T, Acc); 1491analyze_darwin_system_profiler2([[H1,H2]|T], Acc) -> 1492 analyze_darwin_system_profiler2(T, [{H1, string:trim(H2)}|Acc]); 1493analyze_darwin_system_profiler2([[H|TH0]|T], Acc) -> 1494 %% Some value parts has ':' in them, so put them together 1495 TH1 = colonize(TH0), 1496 analyze_darwin_system_profiler2(T, [{H, string:trim(TH1)}|Acc]). 1497 1498%% This is only called if the length is at least 2 1499colonize([L1, L2]) -> 1500 L1 ++ ":" ++ L2; 1501colonize([H|T]) -> 1502 H ++ ":" ++ colonize(T). 1503 1504 1505%% The memory looks like this "<size> <unit>". Example: "2 GB" 1506analyze_darwin_memory_to_factor(Mem) -> 1507 case [string:to_lower(S) || S <- string:tokens(Mem, [$\ ])] of 1508 [_SzStr, "tb"] -> 1509 1; 1510 [SzStr, "gb"] -> 1511 try list_to_integer(SzStr) of 1512 Sz when Sz < 2 -> 1513 20; 1514 Sz when Sz < 4 -> 1515 10; 1516 Sz when Sz < 8 -> 1517 5; 1518 Sz when Sz < 16 -> 1519 2; 1520 _ -> 1521 1 1522 catch 1523 _:_:_ -> 1524 20 1525 end; 1526 [_SzStr, "mb"] -> 1527 20; 1528 _ -> 1529 20 1530 end. 1531 1532 1533%% The speed is a string: "<speed> <unit>" 1534%% the speed may be a float, which we transforms into an integer of MHz. 1535%% To calculate a factor based on processor speed, number of procs 1536%% and number of cores is ... not an exact ... science ... 1537analyze_darwin_cpu_to_factor(_ProcName, 1538 ProcSpeedStr, NumProcStr, NumCoresStr) -> 1539 Speed = 1540 case [string:to_lower(S) || S <- string:tokens(ProcSpeedStr, [$\ ])] of 1541 [SpeedStr, "mhz"] -> 1542 try list_to_integer(SpeedStr) of 1543 SpeedI -> 1544 SpeedI 1545 catch 1546 _:_:_ -> 1547 try list_to_float(SpeedStr) of 1548 SpeedF -> 1549 trunc(SpeedF) 1550 catch 1551 _:_:_ -> 1552 -1 1553 end 1554 end; 1555 [SpeedStr, "ghz"] -> 1556 try list_to_float(SpeedStr) of 1557 SpeedF -> 1558 trunc(1000*SpeedF) 1559 catch 1560 _:_:_ -> 1561 try list_to_integer(SpeedStr) of 1562 SpeedI -> 1563 1000*SpeedI 1564 catch 1565 _:_:_ -> 1566 -1 1567 end 1568 end; 1569 _ -> 1570 -1 1571 end, 1572 NumProc = try list_to_integer(NumProcStr) of 1573 NumProcI -> 1574 NumProcI 1575 catch 1576 _:_:_ -> 1577 1 1578 end, 1579 NumCores = try list_to_integer(NumCoresStr) of 1580 NumCoresI -> 1581 NumCoresI 1582 catch 1583 _:_:_ -> 1584 1 1585 end, 1586 if 1587 (Speed > 3000) -> 1588 if 1589 (NumProc =:= 1) -> 1590 if 1591 (NumCores < 2) -> 1592 5; 1593 (NumCores < 4) -> 1594 3; 1595 (NumCores < 6) -> 1596 2; 1597 true -> 1598 1 1599 end; 1600 true -> 1601 if 1602 (NumCores < 4) -> 1603 2; 1604 true -> 1605 1 1606 end 1607 end; 1608 (Speed > 2000) -> 1609 if 1610 (NumProc =:= 1) -> 1611 if 1612 (NumCores < 2) -> 1613 8; 1614 (NumCores < 4) -> 1615 5; 1616 (NumCores < 6) -> 1617 3; 1618 true -> 1619 1 1620 end; 1621 true -> 1622 if 1623 (NumCores < 4) -> 1624 5; 1625 (NumCores < 8) -> 1626 2; 1627 true -> 1628 1 1629 end 1630 end; 1631 true -> 1632 if 1633 (NumProc =:= 1) -> 1634 if 1635 (NumCores < 2) -> 1636 10; 1637 (NumCores < 4) -> 1638 7; 1639 (NumCores < 6) -> 1640 5; 1641 (NumCores < 8) -> 1642 3; 1643 true -> 1644 1 1645 end; 1646 true -> 1647 if 1648 (NumCores < 4) -> 1649 8; 1650 (NumCores < 8) -> 1651 4; 1652 true -> 1653 1 1654 end 1655 end 1656 end. 1657 1658 1659analyze_and_print_solaris_host_info(Version) -> 1660 Release = 1661 case file:read_file_info("/etc/release") of 1662 {ok, _} -> 1663 case [string:trim(S) || S <- string:tokens(os:cmd("cat /etc/release"), [$\n])] of 1664 [Rel | _] -> 1665 Rel; 1666 _ -> 1667 "-" 1668 end; 1669 _ -> 1670 "-" 1671 end, 1672 %% Display the firmware device tree root properties (prtconf -b) 1673 Props = [list_to_tuple([string:trim(PS) || PS <- Prop]) || 1674 Prop <- [string:tokens(S, [$:]) || 1675 S <- string:tokens(os:cmd("prtconf -b"), [$\n])]], 1676 BannerName = case lists:keysearch("banner-name", 1, Props) of 1677 {value, {_, BN}} -> 1678 string:trim(BN); 1679 _ -> 1680 "-" 1681 end, 1682 InstructionSet = 1683 case string:trim(os:cmd("isainfo -k")) of 1684 "Pseudo-terminal will not" ++ _ -> 1685 "-"; 1686 IS -> 1687 IS 1688 end, 1689 PtrConf = [list_to_tuple([string:trim(S) || S <- Items]) || Items <- [string:tokens(S, [$:]) || S <- string:tokens(os:cmd("prtconf"), [$\n])], length(Items) > 1], 1690 SysConf = 1691 case lists:keysearch("System Configuration", 1, PtrConf) of 1692 {value, {_, SC}} -> 1693 SC; 1694 _ -> 1695 "-" 1696 end, 1697 NumPhysProc = 1698 begin 1699 NPPStr = string:trim(os:cmd("psrinfo -p")), 1700 try list_to_integer(NPPStr) of 1701 _ -> 1702 NPPStr 1703 catch 1704 _:_:_ -> 1705 "-" 1706 end 1707 end, 1708 NumProc = try integer_to_list(length(string:tokens(os:cmd("psrinfo"), [$\n]))) of 1709 NPStr -> 1710 NPStr 1711 catch 1712 _:_:_ -> 1713 "-" 1714 end, 1715 MemSz = 1716 case lists:keysearch("Memory size", 1, PtrConf) of 1717 {value, {_, MS}} -> 1718 MS; 1719 _ -> 1720 "-" 1721 end, 1722 io:format("Solaris: ~s" 1723 "~n Release: ~s" 1724 "~n Banner Name: ~s" 1725 "~n Instruction Set: ~s" 1726 "~n CPUs: ~s (~s)" 1727 "~n System Config: ~s" 1728 "~n Memory Size: ~s" 1729 "~n Num Online Schedulers: ~s" 1730 "~n~n", [Version, Release, BannerName, InstructionSet, 1731 NumPhysProc, NumProc, 1732 SysConf, MemSz, 1733 str_num_schedulers()]), 1734 MemFactor = 1735 try string:tokens(MemSz, [$ ]) of 1736 [SzStr, "Mega" ++ _] -> 1737 try list_to_integer(SzStr) of 1738 Sz when Sz > 8192 -> 1739 0; 1740 Sz when Sz > 4096 -> 1741 1; 1742 Sz when Sz > 2048 -> 1743 2; 1744 _ -> 1745 5 1746 catch 1747 _:_:_ -> 1748 10 1749 end; 1750 [SzStr, "Giga" ++ _] -> 1751 try list_to_integer(SzStr) of 1752 Sz when Sz > 8 -> 1753 0; 1754 Sz when Sz > 4 -> 1755 1; 1756 Sz when Sz > 2 -> 1757 2; 1758 _ -> 1759 5 1760 catch 1761 _:_:_ -> 1762 10 1763 end; 1764 _ -> 1765 10 1766 catch 1767 _:_:_ -> 1768 10 1769 end, 1770 {try erlang:system_info(schedulers) of 1771 1 -> 1772 10; 1773 2 -> 1774 5; 1775 N when (N =< 6) -> 1776 2; 1777 _ -> 1778 1 1779 catch 1780 _:_:_ -> 1781 10 1782 end + MemFactor, []}. 1783 1784 1785analyze_and_print_win_host_info(Version) -> 1786 SysInfo = which_win_system_info(), 1787 OsName = win_sys_info_lookup(os_name, SysInfo), 1788 OsVersion = win_sys_info_lookup(os_version, SysInfo), 1789 SysMan = win_sys_info_lookup(system_manufacturer, SysInfo), 1790 SysMod = win_sys_info_lookup(system_model, SysInfo), 1791 NumProcs = win_sys_info_lookup(num_processors, SysInfo), 1792 TotPhysMem = win_sys_info_lookup(total_phys_memory, SysInfo), 1793 io:format("Windows: ~s" 1794 "~n OS Version: ~s (~p)" 1795 "~n System Manufacturer: ~s" 1796 "~n System Model: ~s" 1797 "~n Number of Processor(s): ~s" 1798 "~n Total Physical Memory: ~s" 1799 "~n Num Online Schedulers: ~s" 1800 "~n", [OsName, OsVersion, Version, 1801 SysMan, SysMod, NumProcs, TotPhysMem, 1802 str_num_schedulers()]), 1803 MemFactor = 1804 try 1805 begin 1806 [MStr, MUnit|_] = 1807 string:tokens(lists:delete($,, TotPhysMem), [$\ ]), 1808 case string:to_lower(MUnit) of 1809 "gb" -> 1810 try list_to_integer(MStr) of 1811 M when M > 8 -> 1812 0; 1813 M when M > 4 -> 1814 1; 1815 M when M > 2 -> 1816 2; 1817 _ -> 1818 5 1819 catch 1820 _:_:_ -> 1821 10 1822 end; 1823 "mb" -> 1824 try list_to_integer(MStr) of 1825 M when M > 8192 -> 1826 0; 1827 M when M > 4096 -> 1828 1; 1829 M when M > 2048 -> 1830 2; 1831 _ -> 1832 5 1833 catch 1834 _:_:_ -> 1835 10 1836 end; 1837 _ -> 1838 10 1839 end 1840 end 1841 catch 1842 _:_:_ -> 1843 10 1844 end, 1845 CPUFactor = 1846 case erlang:system_info(schedulers) of 1847 1 -> 1848 10; 1849 2 -> 1850 5; 1851 _ -> 1852 2 1853 end, 1854 {CPUFactor + MemFactor, SysInfo}. 1855 1856win_sys_info_lookup(Key, SysInfo) -> 1857 win_sys_info_lookup(Key, SysInfo, "-"). 1858 1859win_sys_info_lookup(Key, SysInfo, Def) -> 1860 case lists:keysearch(Key, 1, SysInfo) of 1861 {value, {Key, Value}} -> 1862 Value; 1863 false -> 1864 Def 1865 end. 1866 1867%% This function only extracts the prop we actually care about! 1868which_win_system_info() -> 1869 F = fun() -> 1870 try 1871 begin 1872 SysInfo = os:cmd("systeminfo"), 1873 process_win_system_info( 1874 string:tokens(SysInfo, [$\r, $\n]), []) 1875 end 1876 catch 1877 C:E:S -> 1878 io:format("Failed get or process System info: " 1879 " Error Class: ~p" 1880 " Error: ~p" 1881 " Stack: ~p" 1882 "~n", [C, E, S]), 1883 [] 1884 end 1885 end, 1886 proxy_call(F, minutes(1), 1887 fun() -> throw({skip, "System info timeout"}) end). 1888 1889process_win_system_info([], Acc) -> 1890 Acc; 1891process_win_system_info([H|T], Acc) -> 1892 case string:tokens(H, [$:]) of 1893 [Key, Value] -> 1894 case string:to_lower(Key) of 1895 "os name" -> 1896 process_win_system_info(T, 1897 [{os_name, string:trim(Value)}|Acc]); 1898 "os version" -> 1899 process_win_system_info(T, 1900 [{os_version, string:trim(Value)}|Acc]); 1901 "system manufacturer" -> 1902 process_win_system_info(T, 1903 [{system_manufacturer, string:trim(Value)}|Acc]); 1904 "system model" -> 1905 process_win_system_info(T, 1906 [{system_model, string:trim(Value)}|Acc]); 1907 "processor(s)" -> 1908 [NumProcStr|_] = string:tokens(Value, [$\ ]), 1909 T2 = lists:nthtail(list_to_integer(NumProcStr), T), 1910 process_win_system_info(T2, 1911 [{num_processors, NumProcStr}|Acc]); 1912 "total physical memory" -> 1913 process_win_system_info(T, 1914 [{total_phys_memory, string:trim(Value)}|Acc]); 1915 _ -> 1916 process_win_system_info(T, Acc) 1917 end; 1918 _ -> 1919 process_win_system_info(T, Acc) 1920 end. 1921 1922 1923linux_info_lookup(Key, File) -> 1924 try [string:trim(S) || S <- string:tokens(os:cmd("grep " ++ "\"" ++ Key ++ "\"" ++ " " ++ File), [$:,$\n])] of 1925 Info -> 1926 linux_info_lookup_collect(Key, Info, []) 1927 catch 1928 _:_:_ -> 1929 "-" 1930 end. 1931 1932linux_info_lookup_collect(_Key, [], Values) -> 1933 lists:reverse(Values); 1934linux_info_lookup_collect(Key, [Key, Value|Rest], Values) -> 1935 linux_info_lookup_collect(Key, Rest, [Value|Values]); 1936linux_info_lookup_collect(_, _, Values) -> 1937 lists:reverse(Values). 1938 1939 1940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1941%% Set kill timer 1942 1943set_kill_timer(Config) -> 1944 case init:get_argument(megaco_test_timeout) of 1945 {ok, _} -> 1946 Config; 1947 _ -> 1948 Time = 1949 case lookup_config(tc_timeout, Config) of 1950 [] -> 1951 timer:minutes(5); 1952 ConfigTime when is_integer(ConfigTime) -> 1953 ConfigTime 1954 end, 1955 Dog = test_server:timetrap(Time), 1956 [{kill_timer, Dog}|Config] 1957 1958 1959 end. 1960 1961reset_kill_timer(Config) -> 1962 case lists:keysearch(kill_timer, 1, Config) of 1963 {value, {kill_timer, Dog}} -> 1964 test_server:timetrap_cancel(Dog), 1965 lists:keydelete(kill_timer, 1, Config); 1966 _ -> 1967 Config 1968 end. 1969 1970 1971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1972 1973try_tc(TCName, Name, Verbosity, Pre, Case, Post) 1974 when is_function(Pre, 0) andalso 1975 is_function(Case, 1) andalso 1976 is_function(Post, 1) -> 1977 process_flag(trap_exit, true), 1978 put(verbosity, Verbosity), 1979 put(sname, Name), 1980 put(tc, TCName), 1981 p("try_tc -> starting: try pre"), 1982 try Pre() of 1983 State -> 1984 p("try_tc -> pre done: try test case"), 1985 try Case(State) of 1986 Res -> 1987 p("try_tc -> test case done: try post"), 1988 (catch Post(State)), 1989 p("try_tc -> done"), 1990 Res 1991 catch 1992 throw:{skip, _} = SKIP:_ -> 1993 p("try_tc -> test case (throw) skip: try post"), 1994 (catch Post(State)), 1995 p("try_tc -> test case (throw) skip: done"), 1996 SKIP; 1997 exit:{skip, _} = SKIP:_ -> 1998 p("try_tc -> test case (exit) skip: try post"), 1999 (catch Post(State)), 2000 p("try_tc -> test case (exit) skip: done"), 2001 SKIP; 2002 C:E:S -> 2003 p("try_tc -> test case failed: try post"), 2004 (catch Post(State)), 2005 case megaco_test_global_sys_monitor:events() of 2006 [] -> 2007 p("try_tc -> test case failed: done"), 2008 exit({case_catched, C, E, S}); 2009 SysEvs -> 2010 p("try_tc -> test case failed with system event(s): " 2011 "~n ~p", [SysEvs]), 2012 {skip, "TC failure with system events"} 2013 end 2014 end 2015 catch 2016 throw:{skip, _} = SKIP:_ -> 2017 p("try_tc -> pre (throw) skip"), 2018 SKIP; 2019 exit:{skip, _} = SKIP:_ -> 2020 p("try_tc -> pre (exit) skip"), 2021 SKIP; 2022 C:E:S -> 2023 case megaco_test_global_sys_monitor:events() of 2024 [] -> 2025 p("try_tc -> pre failed: done"), 2026 exit({pre_catched, C, E, S}); 2027 SysEvs -> 2028 p("try_tc -> pre failed with system event(s): " 2029 "~n ~p", [SysEvs]), 2030 {skip, "TC pre failure with system events"} 2031 end 2032 end. 2033 2034 2035 2036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2037 2038prepare_test_case(Actions, N, Config, File, Line) -> 2039 OrigNodes = lookup_config(nodes, Config), 2040 TestNodes = lookup_config(nodenames, Config), %% For testserver 2041 This = node(), 2042 SomeNodes = OrigNodes ++ (TestNodes -- OrigNodes), 2043 AllNodes = [This | (SomeNodes -- [This])], 2044 Nodes = pick_n_nodes(N, AllNodes, File, Line), 2045 start_nodes(Nodes, File, Line), 2046 do_prepare_test_case(Actions, Nodes, Config, File, Line). 2047 2048do_prepare_test_case([init | Actions], Nodes, Config, File, Line) -> 2049 process_flag(trap_exit, true), 2050 megaco_test_lib:flush(), 2051 do_prepare_test_case(Actions, Nodes, Config, File, Line); 2052do_prepare_test_case([{stop_app, App} | Actions], Nodes, Config, File, Line) -> 2053 _Res = rpc:multicall(Nodes, application, stop, [App]), 2054 do_prepare_test_case(Actions, Nodes, Config, File, Line); 2055do_prepare_test_case([], Nodes, _Config, _File, _Line) -> 2056 Nodes. 2057 2058pick_n_nodes(all, AllNodes, _File, _Line) -> 2059 AllNodes; 2060pick_n_nodes(N, AllNodes, _File, _Line) 2061 when is_integer(N) andalso (length(AllNodes) >= N) -> 2062 AllNodes -- lists:nthtail(N, AllNodes); 2063pick_n_nodes(N, AllNodes, File, Line) -> 2064 fatal_skip({too_few_nodes, N, AllNodes}, File, Line). 2065 2066lookup_config(Key,Config) -> 2067 case lists:keysearch(Key, 1, Config) of 2068 {value,{Key,Val}} -> 2069 Val; 2070 _ -> 2071 [] 2072 end. 2073 2074mk_nodes(N) when (N > 0) -> 2075 mk_nodes(N, []). 2076 2077mk_nodes(0, Nodes) -> 2078 Nodes; 2079mk_nodes(N, []) -> 2080 mk_nodes(N - 1, [node()]); 2081mk_nodes(N, Nodes) when N > 0 -> 2082 Head = hd(Nodes), 2083 [Name, Host] = node_to_name_and_host(Head), 2084 Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)]. 2085 2086mk_node(N, Name, Host) -> 2087 list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). 2088 2089%% Returns [Name, Host] 2090node_to_name_and_host(Node) -> 2091 string:tokens(atom_to_list(Node), [$@]). 2092 2093 2094start_nodes(Nodes, File, Line) when is_list(Nodes) -> 2095 start_nodes(Nodes, false, File, Line). 2096 2097start_nodes(Nodes, Force, File, Line) 2098 when is_list(Nodes) andalso is_boolean(Force) -> 2099 start_nodes(Nodes, Force, File, Line, []). 2100 2101start_nodes([], _Force, _File, _Line, _Started) -> 2102 ok; 2103start_nodes([Node|Nodes], Force, File, Line, Started) -> 2104 try start_node(Node, Force, true, File, Line) of 2105 ok -> 2106 start_nodes(Nodes, Force, File, Line, [Node|Started]) 2107 catch 2108 exit:{skip, _} = SKIP:_ -> 2109 (catch stop_nodes(lists:reverse(Started), File, Line)), 2110 exit(SKIP); 2111 C:E:S -> 2112 (catch stop_nodes(lists:reverse(Started), File, Line)), 2113 erlang:raise(C, E, S) 2114 end. 2115 2116start_node(Node, File, Line) -> 2117 start_node(Node, false, false, File, Line). 2118 2119start_node(Node, Force, File, Line) 2120 when is_atom(Node) andalso is_boolean(Force) -> 2121 start_node(Node, Force, false, File, Line). 2122 2123start_node(Node, Force, Retry, File, Line) -> 2124 case net_adm:ping(Node) of 2125 %% Do not require a *new* node 2126 pong when (Force =:= false) -> 2127 p("node ~p already running", [Node]), 2128 ok; 2129 2130 %% Do require a *new* node, so kill this one and try again 2131 pong when ((Force =:= true) andalso (Retry =:= true)) -> 2132 e("node ~p already running - kill and retry", [Node]), 2133 case stop_node(Node) of 2134 ok -> 2135 start_node(Node, Force, false, File, Line); 2136 error -> 2137 e("node ~p already running - failed kill (no retry)", [Node]), 2138 fatal_skip({node_already_running, Node}, File, Line) 2139 end; 2140 2141 %% Do require a *new* node, but no retry so give up and fail 2142 pong when (Force =:= true) -> 2143 e("node ~p already running", [Node]), 2144 fatal_skip({node_already_running, Node}, File, Line); 2145 2146 % Not (yet) running 2147 pang -> 2148 [Name, Host] = node_to_name_and_host(Node), 2149 Pa = filename:dirname(code:which(?MODULE)), 2150 Args = " -pa " ++ Pa ++ 2151 " -s " ++ atom_to_list(megaco_test_sys_monitor) ++ " start" ++ 2152 " -s global sync", 2153 p("try start node ~p", [Node]), 2154 case slave:start_link(Host, Name, Args) of 2155 {ok, NewNode} when NewNode =:= Node -> 2156 p("node ~p started - now set path, cwd and sync", [Node]), 2157 Path = code:get_path(), 2158 {ok, Cwd} = file:get_cwd(), 2159 true = rpc:call(Node, code, set_path, [Path]), 2160 ok = rpc:call(Node, file, set_cwd, [Cwd]), 2161 true = rpc:call(Node, code, set_path, [Path]), 2162 {_, []} = rpc:multicall(global, sync, []), 2163 ok; 2164 Other -> 2165 e("failed starting node ~p: ~p", [Node, Other]), 2166 fatal_skip({cannot_start_node, Node, Other}, File, Line) 2167 end 2168 end. 2169 2170 2171stop_nodes(Nodes, File, Line) when is_list(Nodes) -> 2172 stop_nodes(Nodes, [], File, Line). 2173 2174stop_nodes([], [], _File, _Line) -> 2175 ok; 2176stop_nodes([], StillRunning, File, Line) -> 2177 e("Failed stopping nodes: " 2178 "~n ~p", [StillRunning]), 2179 fatal_skip({failed_stop_nodes, lists:reverse(StillRunning)}, File, Line); 2180stop_nodes([Node|Nodes], Acc, File, Line) -> 2181 case stop_node(Node) of 2182 ok -> 2183 stop_nodes(Nodes, Acc, File, Line); 2184 error -> 2185 stop_nodes(Nodes, [Node|Acc], File, Line) 2186 end. 2187 2188 2189stop_node(Node, File, Line) when is_atom(Node) -> 2190 p("try stop node ~p", [Node]), 2191 case stop_node(Node) of 2192 ok -> 2193 ok; 2194 error -> 2195 fatal_skip({failed_stop_node, Node}, File, Line) 2196 end. 2197 2198stop_node(Node) -> 2199 p("try stop node ~p", [Node]), 2200 erlang:monitor_node(Node, true), 2201 rpc:call(Node, erlang, halt, []), 2202 receive 2203 {nodedown, Node} -> 2204 ok 2205 after 10000 -> 2206 e("failed stop node ~p", [Node]), 2207 error 2208 end. 2209 2210 2211 2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2213 2214f(F, A) -> 2215 lists:flatten(io_lib:format(F, A)). 2216 2217e(F, A) -> 2218 print("ERROR", F, A). 2219 2220p(F) -> 2221 p(F, []). 2222 2223p(F, A) -> 2224 print("INFO", F, A). 2225 2226print(Pre, F, A) -> 2227 io:format("*** [~s] [~s] ~p " ++ F ++ "~n", [?FTS(), Pre, self() | A]). 2228 2229 2230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2231 2232explicit_inet_backend() -> 2233 %% This is intentional! 2234 %% This is a kernel flag, which if set disables 2235 %% our own special handling of the inet_backend 2236 %% in our test suites. 2237 case application:get_all_env(kernel) of 2238 Env when is_list(Env) -> 2239 case lists:keysearch(inet_backend, 1, Env) of 2240 {value, {inet_backend, _}} -> 2241 true; 2242 _ -> 2243 false 2244 end; 2245 _ -> 2246 false 2247 end. 2248 2249test_inet_backends() -> 2250 case init:get_argument(megaco) of 2251 {ok, SnmpArgs} when is_list(SnmpArgs) -> 2252 test_inet_backends(SnmpArgs, atom_to_list(?FUNCTION_NAME)); 2253 error -> 2254 false 2255 end. 2256 2257test_inet_backends([], _) -> 2258 false; 2259test_inet_backends([[Key, Val] | _], Key) -> 2260 case list_to_atom(string:to_lower(Val)) of 2261 Bool when is_boolean(Bool) -> 2262 Bool; 2263 _ -> 2264 false 2265 end; 2266test_inet_backends([_|Args], Key) -> 2267 test_inet_backends(Args, Key). 2268 2269 2270inet_backend_opts(Config) when is_list(Config) -> 2271 case lists:keysearch(socket_create_opts, 1, Config) of 2272 {value, {socket_create_opts, InetBackendOpts}} -> 2273 InetBackendOpts; 2274 false -> 2275 [] 2276 end. 2277 2278is_socket_backend(Config) when is_list(Config) -> 2279 case lists:keysearch(socket_create_opts, 1, Config) of 2280 {value, {socket_create_opts, [{inet_backend, socket}]}} -> 2281 true; 2282 _ -> 2283 false 2284 end. 2285 2286 2287open(Config, Pid, Opts) 2288 when is_list(Config) andalso is_pid(Pid) andalso is_list(Opts) -> 2289 InetBackendOpts = inet_backend_opts(Config), 2290 megaco_udp:open(Pid, InetBackendOpts ++ Opts). 2291 2292listen(Config, Pid, Opts) 2293 when is_list(Config) andalso is_pid(Pid) andalso is_list(Opts) -> 2294 InetBackendOpts = inet_backend_opts(Config), 2295 megaco_tcp:listen(Pid, InetBackendOpts ++ Opts). 2296 2297connect(Config, Ref, Opts) 2298 when is_list(Config) andalso is_list(Opts) -> 2299 InetBackendOpts = inet_backend_opts(Config), 2300 megaco_tcp:connect(Ref, InetBackendOpts ++ Opts). 2301 2302