aboutsummaryrefslogblamecommitdiffstats
path: root/lib/os_mon/test/cpu_sup_SUITE.erl
blob: 7a8065c591b8c8c134c2ad9ef42d98543875b152 (plain) (tree)
1
2
3
4
5
6
7
8
9


                   
                                                        
  


                                                                   
  






                                                                           



                       
                                           

                               
                          








                                                   
                                              
                                   


                                             
                                  

           


                                         
                                   
           
 


                                        
                                   

       


                                 
 
         
                                 





                                                                 

                                                                 

                                      
        
 
                             


                                        



                         

             


                             

             


                             

              


                              


       
                                    


                                           





                                             
                                           



                                            


                                           





                            

               
                                                  
                                               

                       



                                                            
                                                                                   

                      

                                                              
                                               

                                




                                         
                                                                                   

                       

                                                           


       


                           

                         





                                
                          
                                           




                                                                

                     
                       




                                                                     
                                                         





                                                    
                  



                                        
                   
                                       
                              
                    
                                                       




                                                                                    
                   




                                               
                   















                                                         




                                                                  
                                                       

                                    











                                                         
                                                                     




                                                                
                                           











                                              

        
                                         

                                                           

       
                                                     


                                                            








                                                    


       
                                       
                                                          
                                                  






                                             

                                        
        
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(cpu_sup_SUITE).
-include_lib("common_test/include/ct.hrl").

%% Test server specific exports
-export([all/0, suite/0]).
-export([init_per_suite/1, end_per_suite/1]).
-export([init_per_testcase/2, end_per_testcase/2]).

%% Test cases
-export([load_api/1]).
-export([util_api/1, util_values/1]).
-export([port/1]).
-export([terminate/1, unavailable/1, restart/1]).

init_per_suite(Config) when is_list(Config) ->
    ok = application:start(os_mon),
    Config.

end_per_suite(Config) when is_list(Config) ->
    ok = application:stop(os_mon),
    Config.

init_per_testcase(unavailable, Config) ->
    terminate(Config),
    init_per_testcase(dummy, Config);
init_per_testcase(_Case, Config) ->
    Config.

end_per_testcase(unavailable, Config) ->
    restart(Config),
    end_per_testcase(dummy, Config);
end_per_testcase(_Case, _Config) ->
    ok.

suite() ->
    [{ct_hooks,[ts_install_cth]},
     {timetrap,{minutes,1}}].

all() -> 
    case test_server:os_type() of
        {unix, sunos} ->
            [load_api, util_api, util_values, port, unavailable];
        {unix, linux} ->
            [load_api, util_api, util_values, port, unavailable];
        {unix, freebsd} ->
            [load_api, util_api, util_values, port, unavailable];
        {unix, darwin} ->
            [load_api, util_api, util_values, port, unavailable];
        {unix, _OSname} -> [load_api];
        _OS -> [unavailable]
    end.

%% Test of load API functions
load_api(Config) when is_list(Config) ->

    %% nprocs()
    N = cpu_sup:nprocs(),
    true = is_integer(N),
    true = N>0,
    true = N<1000000,

    %% avg1()
    Load1 = cpu_sup:avg1(),
    true = is_integer(Load1),
    true = Load1>0,

    %% avg5()
    Load5 = cpu_sup:avg5(),
    true = is_integer(Load5),
    true = Load5>0,

    %% avg15()
    Load15 = cpu_sup:avg15(),
    true = is_integer(Load15),
    true = Load15>0,

    ok.

%% Test of utilization API functions
util_api(Config) when is_list(Config) ->
    %% Some useful funs when testing util/1
    BusyP = fun({user, _Share}) -> true;
               ({nice_user, _Share}) -> true;
               ({kernel, _Share}) -> true;
               ({hard_irq, _Share}) -> true;
               ({soft_irq, _Share}) -> true;
               (_) -> false
            end,
    NonBusyP = fun({wait, _Share}) -> true;
                  ({idle, _Share}) -> true;
                  ({steal, _Share}) -> true;
                  (_) -> false
               end,
    Sum = fun({_Tag, X}, Acc) -> Acc+X end,

    %% util()
    Util1 = cpu_sup:util(),
    true = is_number(Util1),
    true = Util1>0,
    Util2 = cpu_sup:util(),
    true = is_number(Util2),
    true = Util2>0,

    %% util([])
    {all, Busy1, NonBusy1, []} = cpu_sup:util([]),
    true = tiny_diff(100.00, Busy1 + NonBusy1),

    %% util([detailed])
    {Cpus2, Busy2, NonBusy2, []} = cpu_sup:util([detailed]),
    true = lists:all(fun(X) -> is_integer(X) end, Cpus2),
    true = lists:all(BusyP, Busy2),
    true = lists:all(NonBusyP, NonBusy2),
    true = tiny_diff(100.00, lists:foldl(Sum,0,Busy2)+lists:foldl(Sum,0,NonBusy2)),

    %% util([per_cpu])
    [{Cpu3, Busy3, NonBusy3, []}|_] = cpu_sup:util([per_cpu]),
    true = is_integer(Cpu3),
    true = tiny_diff(100.00, Busy3 + NonBusy3),

    %% util([detailed, per_cpu])
    [{Cpu4, Busy4, NonBusy4, []}|_] =
    cpu_sup:util([detailed, per_cpu]),
    true = is_integer(Cpu4),
    true = lists:all(BusyP, Busy2),
    true = lists:all(NonBusyP, NonBusy2),
    true = tiny_diff(100.00, lists:foldl(Sum,0,Busy4)+lists:foldl(Sum,0,NonBusy4)),

    %% bad util/1 calls
    {'EXIT',{badarg,_}} = (catch cpu_sup:util(detailed)),
    {'EXIT',{badarg,_}} = (catch cpu_sup:util([detialed])),

    ok.

tiny_diff(A, B) ->
    (abs(A - B) < 1.0e-11).

-define(SPIN_TIME, 1000).

spinner(Parent) ->
    receive
        stop -> Parent ! stopped
    after 0 -> spinner(Parent)
    end.

%% Test utilization values
util_values(Config) when is_list(Config) ->
    NrOfProcessors =
        case erlang:system_info(logical_processors_available) of
            unknown -> 2;
            X -> X
        end,
    Tester = self(),
    Ref = make_ref(),
    Spinner = fun () ->
                      Spinner = self(),
                      NrOfProcesses = NrOfProcessors,
                      Loopers =
                          [spawn_link(fun () -> spinner(Spinner) end)
                           || _ <- lists:seq(1,NrOfProcesses)],
                      receive after ?SPIN_TIME -> ok end,
                      [begin
                           Looper ! stop,
                           receive stopped -> ok end
                       end
                       || Looper <- Loopers],
                      Tester ! Ref
              end,
    Spin = fun () ->
                   spawn_link(Spinner),
                   receive Ref -> ok end
           end,
    cpu_sup:util(),
    receive after ?SPIN_TIME -> ok end,
    LowUtil0 = cpu_sup:util(),
    case LowUtil0 of
        U when U > ((100.0 / NrOfProcessors) * 0.33) ->
            %% We cannot run this test if the system is doing other
            %% work at the same time as the result will be unreliable
            {skip, io_lib:format("CPU utilization was too high (~f%)", [LowUtil0])};
        _ ->
            cpu_sup:util(),
            Spin(),
            HighUtil1 = cpu_sup:util(),

            receive after ?SPIN_TIME -> ok end,
            LowUtil1 = cpu_sup:util(),

            Spin(),
            HighUtil2 = cpu_sup:util(),

            receive after ?SPIN_TIME -> ok end,
            LowUtil2 = cpu_sup:util(),

            Utils = [{high1,HighUtil1}, {low1,LowUtil1},
                     {high2,HighUtil2}, {low2,LowUtil2}],
            io:format("Utils: ~p~n", [Utils]),

            false = LowUtil1 > HighUtil1,
            false = LowUtil1 > HighUtil2,
            false = LowUtil2 > HighUtil1,
            false = LowUtil2 > HighUtil2,

            ok
    end.


% Outdated
% The portprogram is now restarted if killed, and not by os_mon...

%% Test that cpu_sup handles a terminating port program
port(Config) when is_list(Config) ->
    case cpu_sup_os_pid() of
        {ok, PidStr} ->
            %% Monitor cpu_sup
            MonRef = erlang:monitor(process, cpu_sup),
            N1 = cpu_sup:nprocs(),
            true = N1>0,

            %% Kill the port program
            case os:cmd("kill -9 " ++ PidStr) of
                [] ->
                    %% cpu_sup should not terminate
                    receive
                        {'DOWN', MonRef, _, _, Reason} ->
                            ct:fail({unexpected_exit_reason, Reason})
                    after 3000 ->
                              ok
                    end,

                    %% Give cpu_sup time to restart cpu_sup port
                    ct:sleep({seconds, 3}),
                    N2 = cpu_sup:nprocs(),
                    true = N2>0,

                    erlang:demonitor(MonRef),
                    ok;

                Line ->
                    erlang:demonitor(MonRef),
                    {skip, {not_killed, Line}}
            end;
        _ ->
            {skip, os_pid_not_found }
    end.

terminate(Config) when is_list(Config) ->
    ok = application:set_env(os_mon, start_cpu_sup, false),
    _ = supervisor:terminate_child(os_mon_sup, cpu_sup),
    ok.

%% Test correct behaviour when service is unavailable
unavailable(Config) when is_list(Config) ->

    %% Make sure all API functions return their dummy values
    0 = cpu_sup:nprocs(),
    0 = cpu_sup:avg1(),
    0 = cpu_sup:avg5(),
    0 = cpu_sup:avg15(),
    0 = cpu_sup:util(),
    {all,0,0,[]} = cpu_sup:util([]),
    {all,0,0,[]} = cpu_sup:util([detailed]),
    {all,0,0,[]} = cpu_sup:util([per_cpu]),
    {all,0,0,[]} = cpu_sup:util([detailed,per_cpu]),

    ok.

restart(Config) when is_list(Config) ->
    ok = application:set_env(os_mon, start_cpu_sup, true),
    supervisor:restart_child(os_mon_sup, cpu_sup),
    ok.

%% Aux

cpu_sup_os_pid() ->
    Str = os:cmd("ps -e | grep '[c]pu_sup'"),
    case io_lib:fread("~s", Str) of
        {ok, [Pid], _Rest} -> {ok, Pid};
        _ -> {error, pid_not_found}
    end.