1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2020-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-module(kernel_test_lib). 22 23-export([init_per_suite/1, 24 end_per_suite/1]). 25-export([tc_try/3]). 26-export([socket_type/1, 27 listen/3, 28 connect/4, connect/5, 29 open/3, 30 is_socket_backend/1, 31 inet_backend_opts/1, 32 explicit_inet_backend/0, 33 test_inet_backends/0]). 34-export([start_slave_node/2, start_slave_node/3, 35 start_node/3, start_node/4, 36 stop_node/1]). 37-export([f/2, 38 print/1, print/2]). 39-export([good_hosts/1, 40 lookup/3]). 41 42-include("kernel_test_lib.hrl"). 43 44 45%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 46 47init_per_suite([{allow_skip, Allow}|Config]) -> 48 init_per_suite(Allow, Config); 49init_per_suite(Config) -> 50 init_per_suite(true, Config). 51 52init_per_suite(AllowSkip, Config) when is_boolean(AllowSkip) -> 53 54 print("kernel environment: " 55 "~n (kernel) app: ~p" 56 "~n (all) init: ~p" 57 "~n (kernel) init: ~p", 58 [application:get_all_env(kernel), 59 init:get_arguments(), 60 case init:get_argument(kernel) of 61 {ok, Args} -> Args; 62 error -> undefined 63 end]), 64 65 ct:timetrap(timer:minutes(2)), 66 67 try analyze_and_print_host_info() of 68 {Factor, HostInfo} when (AllowSkip =:= true) andalso 69 is_integer(Factor) -> 70 try maybe_skip(HostInfo) of 71 true -> 72 {skip, "Unstable host and/or os (or combo thererof)"}; 73 false -> 74 kernel_test_global_sys_monitor:start(), 75 [{kernel_factor, Factor} | Config] 76 catch 77 throw:{skip, _} = SKIP -> 78 SKIP 79 end; 80 81 {Factor, _HostInfo} when (AllowSkip =:= false) andalso 82 is_integer(Factor) -> 83 [{kernel_factor, Factor} | Config] 84 85 catch 86 throw:{skip, _} = SKIP -> 87 SKIP 88 end. 89 90 91end_per_suite(Config) when is_list(Config) -> 92 kernel_test_global_sys_monitor:stop(), 93 Config. 94 95analyze_and_print_host_info() -> 96 {OsFam, OsName} = os:type(), 97 Version = 98 case os:version() of 99 {Maj, Min, Rel} -> 100 f("~w.~w.~w", [Maj, Min, Rel]); 101 VStr -> 102 VStr 103 end, 104 case {OsFam, OsName} of 105 {unix, linux} -> 106 analyze_and_print_linux_host_info(Version); 107 {unix, openbsd} -> 108 analyze_and_print_openbsd_host_info(Version); 109 {unix, freebsd} -> 110 analyze_and_print_freebsd_host_info(Version); 111 {unix, netbsd} -> 112 analyze_and_print_netbsd_host_info(Version); 113 {unix, darwin} -> 114 analyze_and_print_darwin_host_info(Version); 115 {unix, sunos} -> 116 analyze_and_print_solaris_host_info(Version); 117 {win32, nt} -> 118 analyze_and_print_win_host_info(Version); 119 _ -> 120 io:format("OS Family: ~p" 121 "~n OS Type: ~p" 122 "~n Version: ~p" 123 "~n Num Online Schedulers: ~s" 124 "~n", [OsFam, OsName, Version, str_num_schedulers()]), 125 {num_schedulers_to_factor(), []} 126 end. 127 128linux_which_distro(Version) -> 129 case file:read_file_info("/etc/issue") of 130 {ok, _} -> 131 case [string:trim(S) || 132 S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of 133 [DistroStr|_] -> 134 io:format("Linux: ~s" 135 "~n ~s" 136 "~n", 137 [Version, DistroStr]), 138 case DistroStr of 139 "Wind River Linux" ++ _ -> 140 wind_river; 141 "MontaVista" ++ _ -> 142 montavista; 143 "Yellow Dog" ++ _ -> 144 yellow_dog; 145 _ -> 146 other 147 end; 148 X -> 149 io:format("Linux: ~s" 150 "~n ~p" 151 "~n", 152 [Version, X]), 153 other 154 end; 155 _ -> 156 io:format("Linux: ~s" 157 "~n", [Version]), 158 other 159 end. 160 161analyze_and_print_linux_host_info(Version) -> 162 Distro = 163 case file:read_file_info("/etc/issue") of 164 {ok, _} -> 165 linux_which_distro(Version); 166 _ -> 167 io:format("Linux: ~s" 168 "~n", [Version]), 169 other 170 end, 171 Factor = 172 case (catch linux_which_cpuinfo(Distro)) of 173 {ok, {CPU, BogoMIPS}} -> 174 io:format("CPU: " 175 "~n Model: ~s" 176 "~n BogoMIPS: ~w" 177 "~n Num Online Schedulers: ~s" 178 "~n", [CPU, BogoMIPS, str_num_schedulers()]), 179 if 180 (BogoMIPS > 20000) -> 181 1; 182 (BogoMIPS > 10000) -> 183 2; 184 (BogoMIPS > 5000) -> 185 3; 186 (BogoMIPS > 2000) -> 187 5; 188 (BogoMIPS > 1000) -> 189 8; 190 true -> 191 10 192 end; 193 {ok, CPU} -> 194 io:format("CPU: " 195 "~n Model: ~s" 196 "~n Num Online Schedulers: ~s" 197 "~n", [CPU, str_num_schedulers()]), 198 NumChed = erlang:system_info(schedulers), 199 if 200 (NumChed > 2) -> 201 2; 202 true -> 203 5 204 end; 205 _ -> 206 5 207 end, 208 %% Check if we need to adjust the factor because of the memory 209 try linux_which_meminfo() of 210 AddFactor -> 211 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 212 {Factor + AddFactor, []} 213 catch 214 _:_:_ -> 215 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 216 {Factor, []} 217 end. 218 219linux_cpuinfo_lookup(Key) when is_list(Key) -> 220 linux_info_lookup(Key, "/proc/cpuinfo"). 221 222linux_cpuinfo_cpu() -> 223 case linux_cpuinfo_lookup("cpu") of 224 [Model] -> 225 Model; 226 _ -> 227 "-" 228 end. 229 230linux_cpuinfo_motherboard() -> 231 case linux_cpuinfo_lookup("motherboard") of 232 [MB] -> 233 MB; 234 _ -> 235 "-" 236 end. 237 238linux_cpuinfo_bogomips() -> 239 case linux_cpuinfo_lookup("bogomips") of 240 BMips when is_list(BMips) -> 241 try lists:sum([bogomips_to_int(BM) || BM <- BMips]) 242 catch 243 _:_:_ -> 244 "-" 245 end; 246 _X -> 247 "-" 248 end. 249 250linux_cpuinfo_total_bogomips() -> 251 case linux_cpuinfo_lookup("total bogomips") of 252 [TBM] -> 253 try bogomips_to_int(TBM) 254 catch 255 _:_:_ -> 256 "-" 257 end; 258 _ -> 259 "-" 260 end. 261 262bogomips_to_int(BM) -> 263 try list_to_float(BM) of 264 F -> 265 floor(F) 266 catch 267 _:_:_ -> 268 try list_to_integer(BM) of 269 I -> 270 I 271 catch 272 _:_:_ -> 273 throw(noinfo) 274 end 275 end. 276 277linux_cpuinfo_model() -> 278 case linux_cpuinfo_lookup("model") of 279 [M] -> 280 M; 281 _X -> 282 "-" 283 end. 284 285linux_cpuinfo_platform() -> 286 case linux_cpuinfo_lookup("platform") of 287 [P] -> 288 P; 289 _ -> 290 "-" 291 end. 292 293linux_cpuinfo_model_name() -> 294 case linux_cpuinfo_lookup("model name") of 295 [P|_] -> 296 P; 297 _ -> 298 "-" 299 end. 300 301linux_cpuinfo_processor() -> 302 case linux_cpuinfo_lookup("Processor") of 303 [P] -> 304 P; 305 _ -> 306 "-" 307 end. 308 309linux_which_cpuinfo(montavista) -> 310 CPU = 311 case linux_cpuinfo_cpu() of 312 "-" -> 313 throw(noinfo); 314 Model -> 315 case linux_cpuinfo_motherboard() of 316 "-" -> 317 Model; 318 MB -> 319 Model ++ " (" ++ MB ++ ")" 320 end 321 end, 322 case linux_cpuinfo_bogomips() of 323 "-" -> 324 {ok, CPU}; 325 BMips -> 326 {ok, {CPU, BMips}} 327 end; 328 329linux_which_cpuinfo(yellow_dog) -> 330 CPU = 331 case linux_cpuinfo_cpu() of 332 "-" -> 333 throw(noinfo); 334 Model -> 335 case linux_cpuinfo_motherboard() of 336 "-" -> 337 Model; 338 MB -> 339 Model ++ " (" ++ MB ++ ")" 340 end 341 end, 342 {ok, CPU}; 343 344linux_which_cpuinfo(wind_river) -> 345 CPU = 346 case linux_cpuinfo_model() of 347 "-" -> 348 throw(noinfo); 349 Model -> 350 case linux_cpuinfo_platform() of 351 "-" -> 352 Model; 353 Platform -> 354 Model ++ " (" ++ Platform ++ ")" 355 end 356 end, 357 case linux_cpuinfo_total_bogomips() of 358 "-" -> 359 {ok, CPU}; 360 BMips -> 361 {ok, {CPU, BMips}} 362 end; 363 364%% Check for x86 (Intel or AMD) 365linux_which_cpuinfo(other) -> 366 CPU = 367 case linux_cpuinfo_model_name() of 368 "-" -> 369 %% ARM (at least some distros...) 370 case linux_cpuinfo_processor() of 371 "-" -> 372 case linux_cpuinfo_model() of 373 "-" -> 374 %% Ok, we give up 375 throw(noinfo); 376 Model -> 377 Model 378 end; 379 Proc -> 380 Proc 381 end; 382 ModelName -> 383 ModelName 384 end, 385 case linux_cpuinfo_bogomips() of 386 "-" -> 387 {ok, CPU}; 388 BMips -> 389 {ok, {CPU, BMips}} 390 end. 391 392linux_meminfo_lookup(Key) when is_list(Key) -> 393 linux_info_lookup(Key, "/proc/meminfo"). 394 395linux_meminfo_memtotal() -> 396 case linux_meminfo_lookup("MemTotal") of 397 [X] -> 398 X; 399 _ -> 400 "-" 401 end. 402 403%% We *add* the value this return to the Factor. 404linux_which_meminfo() -> 405 case linux_meminfo_memtotal() of 406 "-" -> 407 0; 408 MemTotal -> 409 io:format("Memory:" 410 "~n ~s" 411 "~n", [MemTotal]), 412 case string:tokens(MemTotal, [$ ]) of 413 [MemSzStr, MemUnit] -> 414 MemSz2 = list_to_integer(MemSzStr), 415 MemSz3 = 416 case string:to_lower(MemUnit) of 417 "kb" -> 418 MemSz2; 419 "mb" -> 420 MemSz2*1024; 421 "gb" -> 422 MemSz2*1024*1024; 423 _ -> 424 throw(noinfo) 425 end, 426 if 427 (MemSz3 >= 8388608) -> 428 0; 429 (MemSz3 >= 4194304) -> 430 1; 431 (MemSz3 >= 2097152) -> 432 3; 433 true -> 434 5 435 end; 436 _X -> 437 0 438 end 439 end. 440 441%% Just to be clear: This is ***not*** scientific... 442analyze_and_print_openbsd_host_info(Version) -> 443 io:format("OpenBSD:" 444 "~n Version: ~p" 445 "~n", [Version]), 446 Extract = 447 fun(Key) -> 448 string:tokens(string:trim(os:cmd("sysctl " ++ Key)), [$=]) 449 end, 450 try 451 begin 452 CPU = 453 case Extract("hw.model") of 454 ["hw.model", Model] -> 455 string:trim(Model); 456 _ -> 457 "-" 458 end, 459 CPUSpeed = 460 case Extract("hw.cpuspeed") of 461 ["hw.cpuspeed", Speed] -> 462 list_to_integer(Speed); 463 _ -> 464 -1 465 end, 466 NCPU = 467 case Extract("hw.ncpufound") of 468 ["hw.ncpufound", N] -> 469 list_to_integer(N); 470 _ -> 471 -1 472 end, 473 Memory = 474 case Extract("hw.physmem") of 475 ["hw.physmem", PhysMem] -> 476 list_to_integer(PhysMem) div 1024; 477 _ -> 478 -1 479 end, 480 io:format("CPU:" 481 "~n Model: ~s" 482 "~n Speed: ~w" 483 "~n N: ~w" 484 "~nMemory:" 485 "~n ~w KB" 486 "~n", [CPU, CPUSpeed, NCPU, Memory]), 487 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 488 CPUFactor = 489 if 490 (CPUSpeed =:= -1) -> 491 1; 492 (CPUSpeed >= 2000) -> 493 if 494 (NCPU >= 4) -> 495 1; 496 (NCPU >= 2) -> 497 2; 498 true -> 499 3 500 end; 501 true -> 502 if 503 (NCPU >= 4) -> 504 2; 505 (NCPU >= 2) -> 506 3; 507 true -> 508 4 509 end 510 end, 511 MemAddFactor = 512 if 513 (Memory =:= -1) -> 514 0; 515 (Memory >= 8388608) -> 516 0; 517 (Memory >= 4194304) -> 518 1; 519 (Memory >= 2097152) -> 520 2; 521 true -> 522 3 523 end, 524 {CPUFactor + MemAddFactor, []} 525 end 526 catch 527 _:_:_ -> 528 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 529 {2, []} 530 end. 531 532analyze_and_print_freebsd_host_info(Version) -> 533 io:format("FreeBSD:" 534 "~n Version: ~p" 535 "~n", [Version]), 536 %% This test require that the program 'sysctl' is in the path. 537 %% First test with 'which sysctl', if that does not work 538 %% try with 'which /sbin/sysctl'. If that does not work either, 539 %% we skip the test... 540 try 541 begin 542 SysCtl = 543 case string:trim(os:cmd("which sysctl")) of 544 [] -> 545 case string:trim(os:cmd("which /sbin/sysctl")) of 546 [] -> 547 throw(sysctl); 548 SC2 -> 549 SC2 550 end; 551 SC1 -> 552 SC1 553 end, 554 Extract = 555 fun(Key) -> 556 string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)), 557 [$:]) 558 end, 559 CPU = analyze_freebsd_cpu(Extract), 560 CPUSpeed = analyze_freebsd_cpu_speed(Extract), 561 NCPU = analyze_freebsd_ncpu(Extract), 562 Memory = analyze_freebsd_memory(Extract), 563 io:format("CPU:" 564 "~n Model: ~s" 565 "~n Speed: ~w" 566 "~n N: ~w" 567 "~n Num Online Schedulers: ~s" 568 "~nMemory:" 569 "~n ~w KB" 570 "~n", 571 [CPU, CPUSpeed, NCPU, str_num_schedulers(), Memory]), 572 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 573 CPUFactor = 574 if 575 (CPUSpeed =:= -1) -> 576 1; 577 (CPUSpeed >= 2000) -> 578 if 579 (NCPU >= 4) -> 580 1; 581 (NCPU >= 2) -> 582 2; 583 true -> 584 3 585 end; 586 true -> 587 if 588 (NCPU =:= -1) -> 589 1; 590 (NCPU >= 4) -> 591 2; 592 (NCPU >= 2) -> 593 3; 594 true -> 595 4 596 end 597 end, 598 MemAddFactor = 599 if 600 (Memory =:= -1) -> 601 0; 602 (Memory >= 8388608) -> 603 0; 604 (Memory >= 4194304) -> 605 1; 606 (Memory >= 2097152) -> 607 2; 608 true -> 609 3 610 end, 611 {CPUFactor + MemAddFactor, []} 612 end 613 catch 614 _:_:_ -> 615 io:format("CPU:" 616 "~n Num Online Schedulers: ~s" 617 "~n", [str_num_schedulers()]), 618 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 619 Factor = case erlang:system_info(schedulers) of 620 1 -> 621 10; 622 2 -> 623 5; 624 _ -> 625 2 626 end, 627 {Factor, []} 628 end. 629 630 631analyze_freebsd_cpu(Extract) -> 632 analyze_freebsd_item(Extract, "hw.model", fun(X) -> X end, "-"). 633 634analyze_freebsd_cpu_speed(Extract) -> 635 analyze_freebsd_item(Extract, 636 "hw.clockrate", 637 fun(X) -> list_to_integer(X) end, 638 -1). 639 640analyze_freebsd_ncpu(Extract) -> 641 analyze_freebsd_item(Extract, 642 "hw.ncpu", 643 fun(X) -> list_to_integer(X) end, 644 -1). 645 646analyze_freebsd_memory(Extract) -> 647 analyze_freebsd_item(Extract, 648 "hw.physmem", 649 fun(X) -> list_to_integer(X) div 1024 end, 650 -1). 651 652analyze_freebsd_item(Extract, Key, Process, Default) -> 653 try 654 begin 655 case Extract(Key) of 656 [Key, Model] -> 657 Process(string:trim(Model)); 658 _ -> 659 Default 660 end 661 end 662 catch 663 _:_:_ -> 664 Default 665 end. 666 667analyze_and_print_netbsd_host_info(Version) -> 668 io:format("NetBSD:" 669 "~n Version: ~p" 670 "~n", [Version]), 671 %% This test require that the program 'sysctl' is in the path. 672 %% First test with 'which sysctl', if that does not work 673 %% try with 'which /sbin/sysctl'. If that does not work either, 674 %% we skip the test... 675 try 676 begin 677 SysCtl = 678 case string:trim(os:cmd("which sysctl")) of 679 [] -> 680 case string:trim(os:cmd("which /sbin/sysctl")) of 681 [] -> 682 throw(sysctl); 683 SC2 -> 684 SC2 685 end; 686 SC1 -> 687 SC1 688 end, 689 Extract = 690 fun(Key) -> 691 [string:trim(S) || 692 S <- 693 string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)), 694 [$=])] 695 end, 696 CPU = analyze_netbsd_cpu(Extract), 697 Machine = analyze_netbsd_machine(Extract), 698 Arch = analyze_netbsd_machine_arch(Extract), 699 CPUSpeed = analyze_netbsd_cpu_speed(Extract), 700 NCPU = analyze_netbsd_ncpu(Extract), 701 Memory = analyze_netbsd_memory(Extract), 702 io:format("CPU:" 703 "~n Model: ~s (~s, ~s)" 704 "~n Speed: ~w MHz" 705 "~n N: ~w" 706 "~n Num Schedulers: ~w" 707 "~nMemory:" 708 "~n ~w KB" 709 "~n", 710 [CPU, Machine, Arch, CPUSpeed, NCPU, 711 erlang:system_info(schedulers), Memory]), 712 CPUFactor = 713 if 714 (CPUSpeed =:= -1) -> 715 1; 716 (CPUSpeed >= 2000) -> 717 if 718 (NCPU >= 4) -> 719 1; 720 (NCPU >= 2) -> 721 2; 722 true -> 723 3 724 end; 725 true -> 726 if 727 (NCPU =:= -1) -> 728 1; 729 (NCPU >= 4) -> 730 2; 731 (NCPU >= 2) -> 732 3; 733 true -> 734 4 735 end 736 end, 737 MemAddFactor = 738 if 739 (Memory =:= -1) -> 740 0; 741 (Memory >= 8388608) -> 742 0; 743 (Memory >= 4194304) -> 744 1; 745 (Memory >= 2097152) -> 746 2; 747 true -> 748 3 749 end, 750 {CPUFactor + MemAddFactor, []} 751 end 752 catch 753 _:_:_ -> 754 io:format("CPU:" 755 "~n Num Schedulers: ~w" 756 "~n", [erlang:system_info(schedulers)]), 757 Factor = case erlang:system_info(schedulers) of 758 1 -> 759 10; 760 2 -> 761 5; 762 _ -> 763 2 764 end, 765 {Factor, []} 766 end. 767 768analyze_netbsd_cpu(Extract) -> 769 analyze_netbsd_item(Extract, "hw.model", fun(X) -> X end, "-"). 770 771analyze_netbsd_machine(Extract) -> 772 analyze_netbsd_item(Extract, "hw.machine", fun(X) -> X end, "-"). 773 774analyze_netbsd_machine_arch(Extract) -> 775 analyze_netbsd_item(Extract, "hw.machine_arch", fun(X) -> X end, "-"). 776 777analyze_netbsd_cpu_speed(Extract) -> 778 analyze_netbsd_item(Extract, "machdep.dmi.processor-frequency", 779 fun(X) -> case string:tokens(X, [$\ ]) of 780 [MHz, "MHz"] -> 781 list_to_integer(MHz); 782 _ -> 783 -1 784 end 785 end, "-"). 786 787analyze_netbsd_ncpu(Extract) -> 788 analyze_netbsd_item(Extract, 789 "hw.ncpu", 790 fun(X) -> list_to_integer(X) end, 791 -1). 792 793analyze_netbsd_memory(Extract) -> 794 analyze_netbsd_item(Extract, 795 "hw.physmem64", 796 fun(X) -> list_to_integer(X) div 1024 end, 797 -1). 798 799analyze_netbsd_item(Extract, Key, Process, Default) -> 800 analyze_freebsd_item(Extract, Key, Process, Default). 801 802%% Model Identifier: Macmini7,1 803%% Processor Name: Intel Core i5 804%% Processor Speed: 2,6 GHz 805%% Number of Processors: 1 806%% Total Number of Cores: 2 807%% L2 Cache (per Core): 256 KB 808%% L3 Cache: 3 MB 809%% Hyper-Threading Technology: Enabled 810%% Memory: 16 GB 811 812analyze_and_print_darwin_host_info(Version) -> 813 %% This stuff is for macOS. 814 %% If we ever tested on a pure darwin machine, 815 %% we need to find some other way to find some info... 816 %% Also, I suppose its possible that we for some other 817 %% reason *fail* to get the info... 818 case analyze_darwin_software_info() of 819 [] -> 820 io:format("Darwin:" 821 "~n Version: ~s" 822 "~n Num Online Schedulers: ~s" 823 "~n", [Version, str_num_schedulers()]), 824 {num_schedulers_to_factor(), []}; 825 SwInfo when is_list(SwInfo) -> 826 SystemVersion = analyze_darwin_sw_system_version(SwInfo), 827 KernelVersion = analyze_darwin_sw_kernel_version(SwInfo), 828 HwInfo = analyze_darwin_hardware_info(), 829 ModelName = analyze_darwin_hw_model_name(HwInfo), 830 ModelId = analyze_darwin_hw_model_identifier(HwInfo), 831 ProcName = analyze_darwin_hw_processor_name(HwInfo), 832 ProcSpeed = analyze_darwin_hw_processor_speed(HwInfo), 833 NumProc = analyze_darwin_hw_number_of_processors(HwInfo), 834 NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), 835 Memory = analyze_darwin_hw_memory(HwInfo), 836 io:format("Darwin:" 837 "~n System Version: ~s" 838 "~n Kernel Version: ~s" 839 "~n Model: ~s (~s)" 840 "~n Processor: ~s (~s, ~s, ~s)" 841 "~n Memory: ~s" 842 "~n Num Online Schedulers: ~s" 843 "~n", [SystemVersion, KernelVersion, 844 ModelName, ModelId, 845 ProcName, ProcSpeed, NumProc, NumCores, 846 Memory, 847 str_num_schedulers()]), 848 CPUFactor = analyze_darwin_cpu_to_factor(ProcName, 849 ProcSpeed, 850 NumProc, 851 NumCores), 852 MemFactor = analyze_darwin_memory_to_factor(Memory), 853 if (MemFactor =:= 1) -> 854 {CPUFactor, []}; 855 true -> 856 {CPUFactor + MemFactor, []} 857 end 858 end. 859 860analyze_darwin_sw_system_version(SwInfo) -> 861 proplists:get_value("system version", SwInfo, "-"). 862 863analyze_darwin_sw_kernel_version(SwInfo) -> 864 proplists:get_value("kernel version", SwInfo, "-"). 865 866analyze_darwin_software_info() -> 867 analyze_darwin_system_profiler("SPSoftwareDataType"). 868 869analyze_darwin_hw_model_name(HwInfo) -> 870 proplists:get_value("model name", HwInfo, "-"). 871 872analyze_darwin_hw_model_identifier(HwInfo) -> 873 proplists:get_value("model identifier", HwInfo, "-"). 874 875analyze_darwin_hw_processor_name(HwInfo) -> 876 proplists:get_value("processor name", HwInfo, "-"). 877 878analyze_darwin_hw_processor_speed(HwInfo) -> 879 proplists:get_value("processor speed", HwInfo, "-"). 880 881analyze_darwin_hw_number_of_processors(HwInfo) -> 882 proplists:get_value("number of processors", HwInfo, "-"). 883 884analyze_darwin_hw_total_number_of_cores(HwInfo) -> 885 proplists:get_value("total number of cores", HwInfo, "-"). 886 887analyze_darwin_hw_memory(HwInfo) -> 888 proplists:get_value("memory", HwInfo, "-"). 889 890analyze_darwin_hardware_info() -> 891 analyze_darwin_system_profiler("SPHardwareDataType"). 892 893%% This basically has the structure: "Key: Value" 894%% But could also be (for example): 895%% "Something:" (which we ignore) 896%% "Key: Value1:Value2" 897analyze_darwin_system_profiler(DataType) -> 898 %% First, make sure the program actually exist: 899 case os:cmd("which system_profiler") of 900 [] -> 901 []; 902 _ -> 903 D0 = os:cmd("system_profiler " ++ DataType), 904 D1 = string:tokens(D0, [$\n]), 905 D2 = [string:trim(S1) || S1 <- D1], 906 D3 = [string:tokens(S2, [$:]) || S2 <- D2], 907 analyze_darwin_system_profiler2(D3) 908 end. 909 910analyze_darwin_system_profiler2(L) -> 911 analyze_darwin_system_profiler2(L, []). 912 913analyze_darwin_system_profiler2([], Acc) -> 914 [{string:to_lower(K), V} || {K, V} <- lists:reverse(Acc)]; 915analyze_darwin_system_profiler2([[_]|T], Acc) -> 916 analyze_darwin_system_profiler2(T, Acc); 917analyze_darwin_system_profiler2([[H1,H2]|T], Acc) -> 918 analyze_darwin_system_profiler2(T, [{H1, string:trim(H2)}|Acc]); 919analyze_darwin_system_profiler2([[H|TH0]|T], Acc) -> 920 %% Some value parts has ':' in them, so put them together 921 TH1 = colonize(TH0), 922 analyze_darwin_system_profiler2(T, [{H, string:trim(TH1)}|Acc]). 923 924%% This is only called if the length is at least 2 925colonize([L1, L2]) -> 926 L1 ++ ":" ++ L2; 927colonize([H|T]) -> 928 H ++ ":" ++ colonize(T). 929 930%% The memory looks like this "<size> <unit>". Example: "2 GB" 931analyze_darwin_memory_to_factor(Mem) -> 932 case [string:to_lower(S) || S <- string:tokens(Mem, [$\ ])] of 933 [_SzStr, "tb"] -> 934 1; 935 [SzStr, "gb"] -> 936 try list_to_integer(SzStr) of 937 Sz when Sz < 2 -> 938 20; 939 Sz when Sz < 4 -> 940 10; 941 Sz when Sz < 8 -> 942 5; 943 Sz when Sz < 16 -> 944 2; 945 _ -> 946 1 947 catch 948 _:_:_ -> 949 20 950 end; 951 [_SzStr, "mb"] -> 952 20; 953 _ -> 954 20 955 end. 956 957%% The speed is a string: "<speed> <unit>" 958%% the speed may be a float, which we transforms into an integer of MHz. 959%% To calculate a factor based on processor speed, number of procs 960%% and number of cores is ... not an exact ... science ... 961analyze_darwin_cpu_to_factor(_ProcName, 962 ProcSpeedStr, NumProcStr, NumCoresStr) -> 963 Speed = 964 case [string:to_lower(S) || S <- string:tokens(ProcSpeedStr, [$\ ])] of 965 [SpeedStr, "mhz"] -> 966 try list_to_integer(SpeedStr) of 967 SpeedI -> 968 SpeedI 969 catch 970 _:_:_ -> 971 try list_to_float(SpeedStr) of 972 SpeedF -> 973 trunc(SpeedF) 974 catch 975 _:_:_ -> 976 -1 977 end 978 end; 979 [SpeedStr, "ghz"] -> 980 try list_to_float(SpeedStr) of 981 SpeedF -> 982 trunc(1000*SpeedF) 983 catch 984 _:_:_ -> 985 try list_to_integer(SpeedStr) of 986 SpeedI -> 987 1000*SpeedI 988 catch 989 _:_:_ -> 990 -1 991 end 992 end; 993 _ -> 994 -1 995 end, 996 NumProc = try list_to_integer(NumProcStr) of 997 NumProcI -> 998 NumProcI 999 catch 1000 _:_:_ -> 1001 1 1002 end, 1003 NumCores = try list_to_integer(NumCoresStr) of 1004 NumCoresI -> 1005 NumCoresI 1006 catch 1007 _:_:_ -> 1008 1 1009 end, 1010 if 1011 (Speed > 3000) -> 1012 if 1013 (NumProc =:= 1) -> 1014 if 1015 (NumCores < 2) -> 1016 5; 1017 (NumCores < 4) -> 1018 3; 1019 (NumCores < 6) -> 1020 2; 1021 true -> 1022 1 1023 end; 1024 true -> 1025 if 1026 (NumCores < 4) -> 1027 2; 1028 true -> 1029 1 1030 end 1031 end; 1032 (Speed > 2000) -> 1033 if 1034 (NumProc =:= 1) -> 1035 if 1036 (NumCores < 2) -> 1037 8; 1038 (NumCores < 4) -> 1039 5; 1040 (NumCores < 6) -> 1041 3; 1042 true -> 1043 1 1044 end; 1045 true -> 1046 if 1047 (NumCores < 4) -> 1048 5; 1049 (NumCores < 8) -> 1050 2; 1051 true -> 1052 1 1053 end 1054 end; 1055 true -> 1056 if 1057 (NumProc =:= 1) -> 1058 if 1059 (NumCores < 2) -> 1060 10; 1061 (NumCores < 4) -> 1062 7; 1063 (NumCores < 6) -> 1064 5; 1065 (NumCores < 8) -> 1066 3; 1067 true -> 1068 1 1069 end; 1070 true -> 1071 if 1072 (NumCores < 4) -> 1073 8; 1074 (NumCores < 8) -> 1075 4; 1076 true -> 1077 1 1078 end 1079 end 1080 end. 1081 1082analyze_and_print_solaris_host_info(Version) -> 1083 Release = 1084 case file:read_file_info("/etc/release") of 1085 {ok, _} -> 1086 case [string:trim(S) || S <- string:tokens(os:cmd("cat /etc/release"), [$\n])] of 1087 [Rel | _] -> 1088 Rel; 1089 _ -> 1090 "-" 1091 end; 1092 _ -> 1093 "-" 1094 end, 1095 %% Display the firmware device tree root properties (prtconf -b) 1096 Props = [list_to_tuple([string:trim(PS) || PS <- Prop]) || 1097 Prop <- [string:tokens(S, [$:]) || 1098 S <- string:tokens(os:cmd("prtconf -b"), [$\n])]], 1099 BannerName = case lists:keysearch("banner-name", 1, Props) of 1100 {value, {_, BN}} -> 1101 string:trim(BN); 1102 _ -> 1103 "-" 1104 end, 1105 InstructionSet = 1106 case string:trim(os:cmd("isainfo -k")) of 1107 "Pseudo-terminal will not" ++ _ -> 1108 "-"; 1109 IS -> 1110 IS 1111 end, 1112 PtrConf = [list_to_tuple([string:trim(S) || S <- Items]) || Items <- [string:tokens(S, [$:]) || S <- string:tokens(os:cmd("prtconf"), [$\n])], length(Items) > 1], 1113 SysConf = 1114 case lists:keysearch("System Configuration", 1, PtrConf) of 1115 {value, {_, SC}} -> 1116 SC; 1117 _ -> 1118 "-" 1119 end, 1120 %% Because we count the lines of the output (which may contain 1121 %% any number of extra crap lines) we need to ensure we only 1122 %% count the "proper" stdout. So send it to a tmp file first 1123 %% and then count its number of lines... 1124 NumPhysCPU = 1125 try 1126 begin 1127 File1 = f("/tmp/psrinfo_p.~s.~w", [os:getpid(), os:system_time()]), 1128 os:cmd("psrinfo -p > " ++ File1), 1129 string:trim(os:cmd("cat " ++ File1)) 1130 end 1131 catch 1132 _:_:_ -> 1133 "-" 1134 end, 1135 %% Because we count the lines of the output (which may contain 1136 %% any number of extra crap lines) we need to ensure we only 1137 %% count the "proper" stdout. So send it to a tmp file first 1138 %% and then count its number of lines... 1139 NumVCPU = 1140 try 1141 begin 1142 File2 = f("/tmp/psrinfo.~s.~w", [os:getpid(), os:system_time()]), 1143 os:cmd("psrinfo > " ++ File2), 1144 [NumVCPUStr | _] = string:tokens(os:cmd("wc -l " ++ File2), [$\ ]), 1145 NumVCPUStr 1146 end 1147 catch 1148 _:_:_ -> 1149 "-" 1150 end, 1151 MemSz = 1152 case lists:keysearch("Memory size", 1, PtrConf) of 1153 {value, {_, MS}} -> 1154 MS; 1155 _ -> 1156 "-" 1157 end, 1158 io:format("Solaris: ~s" 1159 "~n Release: ~s" 1160 "~n Banner Name: ~s" 1161 "~n Instruction Set: ~s" 1162 "~n CPUs: ~s (~s)" 1163 "~n System Config: ~s" 1164 "~n Memory Size: ~s" 1165 "~n Num Online Schedulers: ~s" 1166 "~n~n", [Version, Release, BannerName, InstructionSet, 1167 NumPhysCPU, NumVCPU, 1168 SysConf, MemSz, 1169 str_num_schedulers()]), 1170 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 1171 MemFactor = 1172 try string:tokens(MemSz, [$ ]) of 1173 [SzStr, "Mega" ++ _] -> 1174 try list_to_integer(SzStr) of 1175 Sz when Sz > 8192 -> 1176 0; 1177 Sz when Sz > 4096 -> 1178 1; 1179 Sz when Sz > 2048 -> 1180 2; 1181 _ -> 1182 5 1183 catch 1184 _:_:_ -> 1185 10 1186 end; 1187 [SzStr, "Giga" ++ _] -> 1188 try list_to_integer(SzStr) of 1189 Sz when Sz > 8 -> 1190 0; 1191 Sz when Sz > 4 -> 1192 1; 1193 Sz when Sz > 2 -> 1194 2; 1195 _ -> 1196 5 1197 catch 1198 _:_:_ -> 1199 10 1200 end; 1201 _ -> 1202 10 1203 catch 1204 _:_:_ -> 1205 10 1206 end, 1207 {try erlang:system_info(schedulers) of 1208 1 -> 1209 10; 1210 2 -> 1211 5; 1212 N when (N =< 6) -> 1213 2; 1214 _ -> 1215 1 1216 catch 1217 _:_:_ -> 1218 10 1219 end + MemFactor, []}. 1220 1221analyze_and_print_win_host_info(Version) -> 1222 SysInfo = which_win_system_info(), 1223 OsName = win_sys_info_lookup(os_name, SysInfo), 1224 OsVersion = win_sys_info_lookup(os_version, SysInfo), 1225 SysMan = win_sys_info_lookup(system_manufacturer, SysInfo), 1226 SysMod = win_sys_info_lookup(system_model, SysInfo), 1227 NumProcs = win_sys_info_lookup(num_processors, SysInfo), 1228 TotPhysMem = win_sys_info_lookup(total_phys_memory, SysInfo), 1229 io:format("Windows: ~s" 1230 "~n OS Version: ~s (~p)" 1231 "~n System Manufacturer: ~s" 1232 "~n System Model: ~s" 1233 "~n Number of Processor(s): ~s" 1234 "~n Total Physical Memory: ~s" 1235 "~n Num Online Schedulers: ~s" 1236 "~n~n", [OsName, OsVersion, Version, 1237 SysMan, SysMod, NumProcs, TotPhysMem, 1238 str_num_schedulers()]), 1239 io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), 1240 MemFactor = 1241 try 1242 begin 1243 [MStr, MUnit|_] = 1244 string:tokens(lists:delete($,, TotPhysMem), [$\ ]), 1245 case string:to_lower(MUnit) of 1246 "gb" -> 1247 try list_to_integer(MStr) of 1248 M when M > 8 -> 1249 0; 1250 M when M > 4 -> 1251 1; 1252 M when M > 2 -> 1253 2; 1254 _ -> 1255 5 1256 catch 1257 _:_:_ -> 1258 10 1259 end; 1260 "mb" -> 1261 try list_to_integer(MStr) of 1262 M when M > 8192 -> 1263 0; 1264 M when M > 4096 -> 1265 1; 1266 M when M > 2048 -> 1267 2; 1268 _ -> 1269 5 1270 catch 1271 _:_:_ -> 1272 10 1273 end; 1274 _ -> 1275 10 1276 end 1277 end 1278 catch 1279 _:_:_ -> 1280 10 1281 end, 1282 CPUFactor = 1283 case erlang:system_info(schedulers) of 1284 1 -> 1285 10; 1286 2 -> 1287 5; 1288 _ -> 1289 2 1290 end, 1291 {CPUFactor + MemFactor, SysInfo}. 1292 1293win_sys_info_lookup(Key, SysInfo) -> 1294 win_sys_info_lookup(Key, SysInfo, "-"). 1295 1296win_sys_info_lookup(Key, SysInfo, Def) -> 1297 case lists:keysearch(Key, 1, SysInfo) of 1298 {value, {Key, Value}} -> 1299 Value; 1300 false -> 1301 Def 1302 end. 1303 1304%% This function only extracts the prop we actually care about! 1305which_win_system_info() -> 1306 F = fun() -> 1307 try 1308 begin 1309 SysInfo = os:cmd("systeminfo"), 1310 process_win_system_info( 1311 string:tokens(SysInfo, [$\r, $\n]), []) 1312 end 1313 catch 1314 C:E:S -> 1315 io:format("Failed get or process System info: " 1316 " Error Class: ~p" 1317 " Error: ~p" 1318 " Stack: ~p" 1319 "~n", [C, E, S]), 1320 [] 1321 end 1322 end, 1323 proxy_call(F, timer:minutes(1), []). 1324 1325process_win_system_info([], Acc) -> 1326 Acc; 1327process_win_system_info([H|T], Acc) -> 1328 case string:tokens(H, [$:]) of 1329 [Key, Value] -> 1330 case string:to_lower(Key) of 1331 "os name" -> 1332 process_win_system_info(T, 1333 [{os_name, string:trim(Value)}|Acc]); 1334 "os version" -> 1335 process_win_system_info(T, 1336 [{os_version, string:trim(Value)}|Acc]); 1337 "system manufacturer" -> 1338 process_win_system_info(T, 1339 [{system_manufacturer, string:trim(Value)}|Acc]); 1340 "system model" -> 1341 process_win_system_info(T, 1342 [{system_model, string:trim(Value)}|Acc]); 1343 "processor(s)" -> 1344 [NumProcStr|_] = string:tokens(Value, [$\ ]), 1345 T2 = lists:nthtail(list_to_integer(NumProcStr), T), 1346 process_win_system_info(T2, 1347 [{num_processors, NumProcStr}|Acc]); 1348 "total physical memory" -> 1349 process_win_system_info(T, 1350 [{total_phys_memory, string:trim(Value)}|Acc]); 1351 _ -> 1352 process_win_system_info(T, Acc) 1353 end; 1354 _ -> 1355 process_win_system_info(T, Acc) 1356 end. 1357 1358str_num_schedulers() -> 1359 try erlang:system_info(schedulers_online) of 1360 N -> f("~w", [N]) 1361 catch 1362 _:_:_ -> "-" 1363 end. 1364 1365num_schedulers_to_factor() -> 1366 try erlang:system_info(schedulers_online) of 1367 1 -> 1368 10; 1369 2 -> 1370 5; 1371 N when (N =< 6) -> 1372 2; 1373 _ -> 1374 1 1375 catch 1376 _:_:_ -> 1377 10 1378 end. 1379 1380 1381linux_info_lookup(Key, File) -> 1382 LKey = string:to_lower(Key), 1383 try [string:trim(S) || S <- string:tokens(os:cmd("grep -i " ++ "\"" ++ LKey ++ "\"" ++ " " ++ File), [$:,$\n])] of 1384 Info -> 1385 linux_info_lookup_collect(LKey, Info, []) 1386 catch 1387 _:_:_ -> 1388 "-" 1389 end. 1390 1391linux_info_lookup_collect(_Key, [], Values) -> 1392 lists:reverse(Values); 1393linux_info_lookup_collect(Key, [Key, Value|Rest], Values) -> 1394 linux_info_lookup_collect(Key, Rest, [Value|Values]); 1395linux_info_lookup_collect(Key1, [Key2, Value|Rest], Values) -> 1396 case string:to_lower(Key2) of 1397 Key1 -> 1398 linux_info_lookup_collect(Key1, Rest, [Value|Values]); 1399 _ -> 1400 lists:reverse(Values) 1401 end; 1402linux_info_lookup_collect(_, _, Values) -> 1403 lists:reverse(Values). 1404 1405maybe_skip(_HostInfo) -> 1406 1407 %% We have some crap machines that causes random test case failures 1408 %% for no obvious reason. So, attempt to identify those without actually 1409 %% checking for the host name... 1410 1411 LinuxVersionVerify = 1412 fun(V) when (V > {3,6,11}) -> 1413 false; % OK - No skip 1414 (V) when (V =:= {3,6,11}) -> 1415 case string:trim(os:cmd("cat /etc/issue")) of 1416 "Fedora release 16 " ++ _ -> % Stone age Fedora => Skip 1417 true; 1418 _ -> 1419 false 1420 end; 1421 (V) when (V =:= {3,4,20}) -> 1422 case string:trim(os:cmd("cat /etc/issue")) of 1423 "Wind River Linux 5.0.1.0" ++ _ -> % *Old* Wind River => skip 1424 true; 1425 _ -> 1426 false 1427 end; 1428 (V) when (V =:= {2,6,32}) -> 1429 case string:trim(os:cmd("cat /etc/issue")) of 1430 "Debian GNU/Linux 6.0 " ++ _ -> % Stone age Debian => Skip 1431 true; 1432 _ -> 1433 false 1434 end; 1435 (V) when (V > {2,6,24}) -> 1436 false; % OK - No skip 1437 (V) when (V =:= {2,6,10}) -> 1438 case string:trim(os:cmd("cat /etc/issue")) of 1439 "MontaVista" ++ _ -> % Stone age MontaVista => Skip 1440 %% The real problem is that the machine is *very* slow 1441 true; 1442 _ -> 1443 false 1444 end; 1445 (_) -> 1446 %% We are specifically checking for 1447 %% a *really* old gento... 1448 case string:find(string:strip(os:cmd("uname -a")), "gentoo") of 1449 nomatch -> 1450 false; 1451 _ -> % Stone age gentoo => Skip 1452 true 1453 end 1454 end, 1455 DarwinVersionVerify = 1456 fun(V) when (V > {9, 8, 0}) -> 1457 %% This version is OK: No Skip 1458 false; 1459 (_V) -> 1460 %% This version is *not* ok: Skip 1461 true 1462 end, 1463 SkipWindowsOnVirtual = 1464 %% fun() -> 1465 %% SysMan = win_sys_info_lookup(system_manufacturer, HostInfo), 1466 %% case string:to_lower(SysMan) of 1467 %% "vmware" ++ _ -> 1468 %% true; 1469 %% _ -> 1470 %% false 1471 %% end 1472 %% end, 1473 fun() -> 1474 %% The host has been replaced and the VM has been reinstalled 1475 %% so for now we give it a chance... 1476 false 1477 end, 1478 COND = [{unix, [{linux, LinuxVersionVerify}, 1479 {darwin, DarwinVersionVerify}]}, 1480 {win32, SkipWindowsOnVirtual}], 1481 os_cond_skip(COND). 1482 1483os_cond_skip(any) -> 1484 true; 1485os_cond_skip(Skippable) when is_list(Skippable) -> 1486 os_cond_skip(Skippable, os:type()); 1487os_cond_skip(_Crap) -> 1488 false. 1489 1490os_cond_skip(Skippable, {OsFam, OsName}) -> 1491 os_cond_skip(Skippable, OsFam, OsName); 1492os_cond_skip(Skippable, OsFam) -> 1493 os_cond_skip(Skippable, OsFam, undefined). 1494 1495os_cond_skip(Skippable, OsFam, OsName) -> 1496 %% Check if the entire family is to be skipped 1497 %% Example: [win32, unix] 1498 case lists:member(OsFam, Skippable) of 1499 true -> 1500 true; 1501 false -> 1502 %% Example: [{unix, freebsd}] | [{unix, [freebsd, darwin]}] 1503 case lists:keysearch(OsFam, 1, Skippable) of 1504 {value, {OsFam, OsName}} -> 1505 true; 1506 {value, {OsFam, OsNames}} when is_list(OsNames) -> 1507 %% OsNames is a list of: 1508 %% [atom()|{atom(), function/0 | function/1}] 1509 case lists:member(OsName, OsNames) of 1510 true -> 1511 true; 1512 false -> 1513 os_cond_skip_check(OsName, OsNames) 1514 end; 1515 {value, {OsFam, Check}} when is_function(Check, 0) -> 1516 Check(); 1517 {value, {OsFam, Check}} when is_function(Check, 1) -> 1518 Check(os:version()); 1519 _ -> 1520 false 1521 end 1522 end. 1523 1524%% Performs a check via a provided fun with arity 0 or 1. 1525%% The argument is the result of os:version(). 1526os_cond_skip_check(OsName, OsNames) -> 1527 case lists:keysearch(OsName, 1, OsNames) of 1528 {value, {OsName, Check}} when is_function(Check, 0) -> 1529 Check(); 1530 {value, {OsName, Check}} when is_function(Check, 1) -> 1531 Check(os:version()); 1532 _ -> 1533 false 1534 end. 1535 1536 1537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1538 1539lookup(Key, Config, Default) -> 1540 case lists:keysearch(Key, 1, Config) of 1541 {value, {Key, Val}} -> 1542 Val; 1543 _ -> 1544 Default 1545 end. 1546 1547 1548%% Extract N number of hosts from the config. 1549%% Prepend with the own host. 1550%% If not N number of hosts are available, issue a skip exit. 1551good_hosts(N) when is_integer(N) andalso (N > 0) -> 1552 GoodHosts = ct:get_config(test_hosts, []), 1553 {ok, CurrentHost} = inet:gethostname(), 1554 GoodHosts2 = [CurrentHost] ++ (GoodHosts -- [CurrentHost]), 1555 good_hosts2(GoodHosts2, N). 1556 1557good_hosts2(GoodHosts, N) -> 1558 good_hosts2(GoodHosts, N, []). 1559 1560good_hosts2(_GoodHosts, N, Acc) when (N =:= 0) -> 1561 lists:reverse(Acc); 1562good_hosts2([], _N, _Acc) -> 1563 ?SKIPE("Not enough good hosts"); 1564good_hosts2([H|T], N, Acc) -> 1565 case inet:gethostbyname(H) of 1566 {ok, _} -> 1567 good_hosts2(T, N-1, [H|Acc]); 1568 {error, _} -> 1569 ?P("Host not found: ~p", [H]), 1570 good_hosts2(T, N, Acc) 1571 end. 1572 1573 1574 1575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1576 1577set_tc_name(N) when is_atom(N) -> 1578 set_tc_name(atom_to_list(N)); 1579set_tc_name(N) when is_list(N) -> 1580 put(tc_name, N). 1581 1582%% get_tc_name() -> 1583%% get(tc_name). 1584 1585tc_begin(TC) -> 1586 OldVal = process_flag(trap_exit, true), 1587 put(old_trap_exit, OldVal), 1588 set_tc_name(TC), 1589 tc_print("begin ***", 1590 "~n----------------------------------------------------~n", ""). 1591 1592tc_end(Result) when is_list(Result) -> 1593 OldVal = erase(old_trap_exit), 1594 process_flag(trap_exit, OldVal), 1595 tc_print("done: ~s", [Result], 1596 "", "----------------------------------------------------~n~n"), 1597 ok. 1598 1599%% *** tc_try/2,3 *** 1600%% Case: Basically the test case name 1601%% Cond: A fun that is evaluated before the actual test case 1602%% The point of this is that it can performs checks to 1603%% see if we shall run the test case at all. 1604%% For instance, the test case may only work in specific 1605%% conditions. 1606%% TC: The test case fun 1607tc_try(Case, Cond, TC) 1608 when is_atom(Case) andalso 1609 is_function(Cond, 0) andalso 1610 is_function(TC, 0) -> 1611 tc_begin(Case), 1612 try Cond() of 1613 ok -> 1614 try 1615 begin 1616 TC(), 1617 ?SLEEP(?SECS(1)), 1618 tc_end("ok") 1619 end 1620 catch 1621 C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) -> 1622 %% i("catched[tc] (skip): " 1623 %% "~n C: ~p" 1624 %% "~n SKIP: ~p" 1625 %% "~n", [C, SKIP]), 1626 tc_end( f("skipping(catched,~w,tc)", [C]) ), 1627 SKIP; 1628 C:E:S -> 1629 %% i("catched[tc]: " 1630 %% "~n C: ~p" 1631 %% "~n E: ~p" 1632 %% "~n S: ~p" 1633 %% "~n", [C, E, S]), 1634 tc_end( f("failed(catched,~w,tc)", [C]) ), 1635 erlang:raise(C, E, S) 1636 end; 1637 {skip, _} = SKIP -> 1638 tc_end("skipping(tc)"), 1639 SKIP; 1640 {error, Reason} -> 1641 tc_end("failed(tc)"), 1642 exit({tc_cond_failed, Reason}) 1643 catch 1644 C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) -> 1645 %% i("catched[cond] (skip): " 1646 %% "~n C: ~p" 1647 %% "~n SKIP: ~p" 1648 %% "~n", [C, SKIP]), 1649 tc_end( f("skipping(catched,~w,cond)", [C]) ), 1650 SKIP; 1651 C:E:S -> 1652 %% i("catched[cond]: " 1653 %% "~n C: ~p" 1654 %% "~n E: ~p" 1655 %% "~n S: ~p" 1656 %% "~n", [C, E, S]), 1657 tc_end( f("failed(catched,~w,cond)", [C]) ), 1658 erlang:raise(C, E, S) 1659 end. 1660 1661 1662tc_print(F, Before, After) -> 1663 tc_print(F, [], Before, After). 1664 1665tc_print(F, A, Before, After) -> 1666 Name = tc_which_name(), 1667 FStr = f("*** [~s][~s][~p] " ++ F ++ "~n", 1668 [formated_timestamp(),Name,self()|A]), 1669 io:format(user, Before ++ FStr ++ After, []). 1670 1671tc_which_name() -> 1672 case get(tc_name) of 1673 undefined -> 1674 case get(sname) of 1675 undefined -> 1676 ""; 1677 SName when is_list(SName) -> 1678 SName 1679 end; 1680 Name when is_list(Name) -> 1681 Name 1682 end. 1683 1684 1685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1686 1687start_slave_node(Name, Args) -> 1688 start_slave_node(Name, Args, []). 1689 1690start_slave_node(Name, Args, Opts) -> 1691 start_node(Name, slave, Args, Opts). 1692 1693 1694start_node(Name, Type, Args) -> 1695 start_node(Name, Type, Args, []). 1696 1697start_node(Name, Type, Args, Opts) -> 1698 Pa = filename:dirname(code:which(?MODULE)), 1699 A = Args ++ 1700 " -pa " ++ Pa ++ 1701 " -s " ++ atom_to_list(kernel_test_sys_monitor) ++ " start" ++ 1702 " -s global sync", 1703 case test_server:start_node(Name, Type, [{args, A}|Opts]) of 1704 {ok, _Node} = OK -> 1705 global:sync(), 1706 OK; 1707 ERROR -> 1708 ERROR 1709 end. 1710 1711stop_node(Node) -> 1712 test_server:stop_node(Node). 1713 1714 1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1716 1717timetrap_scale_factor() -> 1718 case (catch test_server:timetrap_scale_factor()) of 1719 {'EXIT', _} -> 1720 1; 1721 N -> 1722 N 1723 end. 1724 1725 1726proxy_call(F, Timeout, Default) 1727 when is_function(F, 0) andalso is_integer(Timeout) andalso (Timeout > 0) -> 1728 {P, M} = erlang:spawn_monitor(fun() -> exit(F()) end), 1729 receive 1730 {'DOWN', M, process, P, Reply} -> 1731 Reply 1732 after Timeout -> 1733 erlang:demonitor(M, [flush]), 1734 exit(P, kill), 1735 Default 1736 end. 1737 1738 1739 1740%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1741 1742socket_type(Config) -> 1743 case is_socket_backend(Config) of 1744 true -> 1745 socket; 1746 false -> 1747 port 1748 end. 1749 1750%% gen_tcp wrappers 1751 1752listen(Config, Port, Opts) -> 1753 InetBackendOpts = inet_backend_opts(Config), 1754 gen_tcp:listen(Port, InetBackendOpts ++ Opts). 1755 1756connect(Config, Host, Port, Opts) -> 1757 InetBackendOpts = inet_backend_opts(Config), 1758 gen_tcp:connect(Host, Port, InetBackendOpts ++ Opts). 1759 1760connect(Config, Host, Port, Opts, Timeout) -> 1761 InetBackendOpts = inet_backend_opts(Config), 1762 gen_tcp:connect(Host, Port, InetBackendOpts ++ Opts, Timeout). 1763 1764 1765%% gen_udp wrappers 1766 1767open(Config, Port, Opts) -> 1768 InetBackendOpts = inet_backend_opts(Config), 1769 gen_udp:open(Port, InetBackendOpts ++ Opts). 1770 1771 1772inet_backend_opts(Config) when is_list(Config) -> 1773 case lists:keysearch(socket_create_opts, 1, Config) of 1774 {value, {socket_create_opts, InetBackendOpts}} -> 1775 InetBackendOpts; 1776 false -> 1777 [] 1778 end. 1779 1780is_socket_backend(Config) when is_list(Config) -> 1781 case lists:keysearch(socket_create_opts, 1, Config) of 1782 {value, {socket_create_opts, [{inet_backend, socket}]}} -> 1783 true; 1784 _ -> 1785 false 1786 end. 1787 1788 1789explicit_inet_backend() -> 1790 case application:get_all_env(kernel) of 1791 Env when is_list(Env) -> 1792 case lists:keysearch(inet_backend, 1, Env) of 1793 {value, {inet_backend, _}} -> 1794 true; 1795 _ -> 1796 false 1797 end; 1798 _ -> 1799 false 1800 end. 1801 1802 1803test_inet_backends() -> 1804 case application:get_all_env(kernel) of 1805 Env when is_list(Env) -> 1806 case lists:keysearch(test_inet_backends, 1, Env) of 1807 {value, {test_inet_backends, true}} -> 1808 true; 1809 _ -> 1810 false 1811 end; 1812 _ -> 1813 false 1814 end. 1815 1816 1817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1818 1819f(F, A) -> 1820 lists:flatten(io_lib:format(F, A)). 1821 1822formated_timestamp() -> 1823 format_timestamp(os:timestamp()). 1824 1825format_timestamp({_N1, _N2, N3} = TS) -> 1826 {_Date, Time} = calendar:now_to_local_time(TS), 1827 {Hour, Min, Sec} = Time, 1828 FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.3.0w", 1829 [Hour, Min, Sec, N3 div 1000]), 1830 lists:flatten(FormatTS). 1831 1832print(F) -> 1833 print(F, []). 1834 1835print(F, A) -> 1836 io:format("~s ~p " ++ F ++ "~n", [formated_timestamp(), self() | A]). 1837