|
| 1 | +%% |
| 2 | +%% %CopyrightBegin% |
| 3 | +%% |
| 4 | +%% Copyright Ericsson AB 2006-2024. 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 | +%%% Common Test Framework Event Handler |
| 22 | +%%% |
| 23 | +%%% This module implements an event handler that the CT Master |
| 24 | +%%% uses to handle status and progress notifications sent to the |
| 25 | +%%% master node during test runs. It also keeps track of the |
| 26 | +%%% details of failures which are used by the CT Master to print |
| 27 | +%%% a summary at the end of its run. This module may be used as a |
| 28 | +%%% template for other event handlers that can be plugged in to |
| 29 | +%%% handle logging and reporting on the master node. |
| 30 | +-module(ct_master_event_fork). |
| 31 | +-moduledoc false. |
| 32 | + |
| 33 | +-behaviour(gen_event). |
| 34 | + |
| 35 | +%% API |
| 36 | +-export([start_link/0, add_handler/0, add_handler/1, stop/0]). |
| 37 | +-export([notify/1, sync_notify/1, get_results/0]). |
| 38 | + |
| 39 | +%% gen_event callbacks |
| 40 | +-export([init/1, handle_event/2, handle_call/2, |
| 41 | + handle_info/2, terminate/2, code_change/3]). |
| 42 | + |
| 43 | +-include_lib("common_test/include/ct_event.hrl"). |
| 44 | +-include_lib("common_test/src/ct_util.hrl"). |
| 45 | + |
| 46 | + |
| 47 | +-record(state, {auto_skipped=[], failed=[]}). |
| 48 | + |
| 49 | +%%==================================================================== |
| 50 | +%% gen_event callbacks |
| 51 | +%%==================================================================== |
| 52 | +%%-------------------------------------------------------------------- |
| 53 | +%% Function: start_link() -> {ok,Pid} | {error,Error} |
| 54 | +%% Description: Creates an event manager. |
| 55 | +%%-------------------------------------------------------------------- |
| 56 | +start_link() -> |
| 57 | + gen_event:start_link({local,?CT_MEVMGR}). |
| 58 | + |
| 59 | +%%-------------------------------------------------------------------- |
| 60 | +%% Function: add_handler() -> ok | {'EXIT',Reason} | term() |
| 61 | +%% Description: Adds an event handler |
| 62 | +%%-------------------------------------------------------------------- |
| 63 | +add_handler() -> |
| 64 | + gen_event:add_handler(?CT_MEVMGR_REF,?MODULE,[]). |
| 65 | +add_handler(Args) -> |
| 66 | + gen_event:add_handler(?CT_MEVMGR_REF,?MODULE,Args). |
| 67 | + |
| 68 | +%%-------------------------------------------------------------------- |
| 69 | +%% Function: stop() -> ok |
| 70 | +%% Description: Stops the event manager |
| 71 | +%%-------------------------------------------------------------------- |
| 72 | +stop() -> |
| 73 | + case flush() of |
| 74 | + {error,Reason} -> |
| 75 | + ct_master_logs_fork:log("Error", |
| 76 | + "No response from CT Master Event.\n" |
| 77 | + "Reason = ~tp\n" |
| 78 | + "Terminating now!\n",[Reason]), |
| 79 | + %% communication with event manager fails, kill it |
| 80 | + catch exit(whereis(?CT_MEVMGR_REF), kill); |
| 81 | + _ -> |
| 82 | + gen_event:stop(?CT_MEVMGR_REF) |
| 83 | + end. |
| 84 | + |
| 85 | +flush() -> |
| 86 | + try gen_event:call(?CT_MEVMGR_REF,?MODULE,flush,1800000) of |
| 87 | + flushing -> |
| 88 | + timer:sleep(1), |
| 89 | + flush(); |
| 90 | + done -> |
| 91 | + ok; |
| 92 | + Error = {error,_} -> |
| 93 | + Error |
| 94 | + catch |
| 95 | + _:Reason -> |
| 96 | + {error,Reason} |
| 97 | + end. |
| 98 | + |
| 99 | +%%-------------------------------------------------------------------- |
| 100 | +%% Function: notify(Event) -> ok |
| 101 | +%% Description: Asynchronous notification to event manager. |
| 102 | +%%-------------------------------------------------------------------- |
| 103 | +notify(Event) -> |
| 104 | + gen_event:notify(?CT_MEVMGR_REF,Event). |
| 105 | + |
| 106 | +%%-------------------------------------------------------------------- |
| 107 | +%% Function: sync_notify(Event) -> ok |
| 108 | +%% Description: Synchronous notification to event manager. |
| 109 | +%%-------------------------------------------------------------------- |
| 110 | +sync_notify(Event) -> |
| 111 | + gen_event:sync_notify(?CT_MEVMGR_REF,Event). |
| 112 | + |
| 113 | +%%-------------------------------------------------------------------- |
| 114 | +%% Function: sync_notify(Event) -> Results |
| 115 | +%% Description: Get the results for auto-skipped and failed test cases. |
| 116 | +%%-------------------------------------------------------------------- |
| 117 | +get_results() -> |
| 118 | + gen_event:call(?CT_MEVMGR_REF,?MODULE,get_results). |
| 119 | + |
| 120 | +%%==================================================================== |
| 121 | +%% gen_event callbacks |
| 122 | +%%==================================================================== |
| 123 | +%%-------------------------------------------------------------------- |
| 124 | +%% Function: init(Args) -> {ok, State} |
| 125 | +%% Description: Whenever a new event handler is added to an event manager, |
| 126 | +%% this function is called to initialize the event handler. |
| 127 | +%%-------------------------------------------------------------------- |
| 128 | +init(_) -> |
| 129 | + ct_util:mark_process(), |
| 130 | + ct_master_logs_fork:log("CT Master Event Handler started","",[]), |
| 131 | + {ok,#state{}}. |
| 132 | + |
| 133 | +%%-------------------------------------------------------------------- |
| 134 | +%% Function: |
| 135 | +%% handle_event(Event, State) -> {ok, State} | |
| 136 | +%% {swap_handler, Args1, State1, Mod2, Args2} | |
| 137 | +%% remove_handler |
| 138 | +%% Description:Whenever an event manager receives an event sent using |
| 139 | +%% gen_event:notify/2 or gen_event:sync_notify/2, this function is called for |
| 140 | +%% each installed event handler to handle the event. |
| 141 | +%%-------------------------------------------------------------------- |
| 142 | +handle_event(#event{name=start_logging,node=Node,data=RunDir},State) -> |
| 143 | + ct_master_logs_fork:log("CT Master Event Handler","Got ~ts from ~w",[RunDir,Node]), |
| 144 | + ct_master_logs_fork:nodedir(Node,RunDir), |
| 145 | + {ok,State}; |
| 146 | + |
| 147 | +handle_event(Event=#event{name=Name,node=Node,data=Data},State) -> |
| 148 | + print("~n=== ~w ===~n", [?MODULE]), |
| 149 | + print("~tw on ~w: ~tp~n", [Name,Node,Data]), |
| 150 | + {ok,maybe_store_event(Event,State)}. |
| 151 | + |
| 152 | +%%-------------------------------------------------------------------- |
| 153 | +%% Function: |
| 154 | +%% handle_call(Request, State) -> {ok, Reply, State} | |
| 155 | +%% {swap_handler, Reply, Args1, State1, |
| 156 | +%% Mod2, Args2} | |
| 157 | +%% {remove_handler, Reply} |
| 158 | +%% Description: Whenever an event manager receives a request sent using |
| 159 | +%% gen_event:call/3,4, this function is called for the specified event |
| 160 | +%% handler to handle the request. |
| 161 | +%%-------------------------------------------------------------------- |
| 162 | +handle_call(get_results,State=#state{auto_skipped=AutoSkipped,failed=Failed}) -> |
| 163 | + {ok,#{ |
| 164 | + auto_skipped => lists:sort(AutoSkipped), |
| 165 | + failed => lists:sort(Failed) |
| 166 | + },State}; |
| 167 | +handle_call(flush,State) -> |
| 168 | + case process_info(self(),message_queue_len) of |
| 169 | + {message_queue_len,0} -> |
| 170 | + {ok,done,State}; |
| 171 | + _ -> |
| 172 | + {ok,flushing,State} |
| 173 | + end. |
| 174 | + |
| 175 | +%%-------------------------------------------------------------------- |
| 176 | +%% Function: |
| 177 | +%% handle_info(Info, State) -> {ok, State} | |
| 178 | +%% {swap_handler, Args1, State1, Mod2, Args2} | |
| 179 | +%% remove_handler |
| 180 | +%% Description: This function is called for each installed event handler when |
| 181 | +%% an event manager receives any other message than an event or a synchronous |
| 182 | +%% request (or a system message). |
| 183 | +%%-------------------------------------------------------------------- |
| 184 | +handle_info(_Info,State) -> |
| 185 | + {ok,State}. |
| 186 | + |
| 187 | +%%-------------------------------------------------------------------- |
| 188 | +%% Function: terminate(Reason, State) -> ok |
| 189 | +%% Description:Whenever an event handler is deleted from an event manager, |
| 190 | +%% this function is called. It should be the opposite of Module:init/1 and |
| 191 | +%% do any necessary cleaning up. |
| 192 | +%%-------------------------------------------------------------------- |
| 193 | +terminate(_Reason,_State) -> |
| 194 | + ct_master_logs_fork:log("CT Master Event Handler stopping","",[]), |
| 195 | + ok. |
| 196 | + |
| 197 | +%%-------------------------------------------------------------------- |
| 198 | +%% Function: code_change(OldVsn, State, Extra) -> {ok, NewState} |
| 199 | +%% Description: Convert process state when code is changed |
| 200 | +%%-------------------------------------------------------------------- |
| 201 | +code_change(_OldVsn,State,_Extra) -> |
| 202 | + {ok,State}. |
| 203 | + |
| 204 | +%%-------------------------------------------------------------------- |
| 205 | +%%% Internal functions |
| 206 | +%%-------------------------------------------------------------------- |
| 207 | + |
| 208 | +print(_Str,_Args) -> |
| 209 | +% io:format(_Str,_Args), |
| 210 | + ok. |
| 211 | + |
| 212 | +maybe_store_event(#event{name=tc_done,node=Node,data={Suite,FuncOrGroup,{auto_skipped,Reason}}},State=#state{auto_skipped=Acc}) -> |
| 213 | + State#state{auto_skipped=[{Node,Suite,FuncOrGroup,Reason}|Acc]}; |
| 214 | +maybe_store_event(#event{name=tc_done,node=Node,data={Suite,FuncOrGroup,{failed,Reason}}},State=#state{failed=Acc}) -> |
| 215 | + State#state{failed=[{Node,Suite,FuncOrGroup,Reason}|Acc]}; |
| 216 | +maybe_store_event(_Event,State) -> |
| 217 | + State. |
0 commit comments