1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2020-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22%%---------------------------------------------------------------------- 23%% Purpose: 24%%---------------------------------------------------------------------- 25-module(megaco_test_command_handler). 26 27%%---------------------------------------------------------------------- 28%% Include files 29%%---------------------------------------------------------------------- 30-include("megaco_test_lib.hrl"). 31 32 33%%---------------------------------------------------------------------- 34%% External exports 35%%---------------------------------------------------------------------- 36-export([ 37 start/4, 38 await_completion/2, 39 40 print/1, print/2 41 ]). 42 43 44%%---------------------------------------------------------------------- 45%% Macros 46%%---------------------------------------------------------------------- 47 48%%---------------------------------------------------------------------- 49%% Records 50%%---------------------------------------------------------------------- 51 52 53%%---------------------------------------------------------------------- 54%% Exported functions 55%%---------------------------------------------------------------------- 56 57start(Node, Commands, InitialState, ShortName) 58 when is_atom(Node) andalso 59 is_list(Commands) andalso 60 is_map(InitialState) andalso 61 is_list(ShortName) -> 62 Fun = fun() -> 63 put(sname, ShortName), 64 process_flag(trap_exit, true), 65 Result = command_handler(Commands, InitialState), 66 print("command handler terminated with: " 67 "~n ~p", [Result]), 68 exit(Result) 69 end, 70 erlang:spawn_link(Node, Fun). 71 72command_handler([], State) -> 73 print("command_handler -> entry when done with" 74 "~n State: ~p", [State]), 75 {ok, State}; 76command_handler([#{id := Id, 77 desc := Desc, 78 cmd := Cmd}|Commands], State) 79 when is_list(Desc) andalso is_function(Cmd, 1) -> 80 print("command_handler -> [~w] ~s", [Id, Desc]), 81 try Cmd(State) of 82 {ok, NewState} -> 83 print("command_handler -> [~w] cmd ok", [Id]), 84 command_handler(Commands, NewState); 85 {skip, _} = SKIP -> 86 print("command_handler -> [~w] cmd skip (returned)", [Id]), 87 SKIP; 88 {error, Reason} -> 89 print("command_handler -> [~w] cmd error: " 90 "~n Reason: ~p", [Id, Reason]), 91 {error, {cmd_error, Reason}} 92 93 catch 94 throw:{skip, _} = SKIP:_ -> 95 print("command_handler -> [~w] cmd skip (throw)", [Id]), 96 SKIP; 97 exit:{skip, _} = SKIP:_ -> 98 print("command_handler -> [~w] cmd skip (exit)", [Id]), 99 SKIP; 100 C:E:S -> 101 print("command_handler -> [~w] cmd failure:" 102 "~n C: ~p" 103 "~n E: ~p" 104 "~n S: ~p", [Id, C, E, S]), 105 {error, {cmd_failure, {C, E, S}}} 106 end. 107 108 109%% --- Await completion of one or more command handler(s) 110 111await_completion(Pids, Timeout) -> 112 await_completion(Pids, [], [], Timeout). 113 114await_completion([], [], _Good, _Timeout) -> 115 print("await_completion -> entry when done (success)"), 116 ok; 117await_completion([], Bad, Good, _Timeout) -> 118 print("await_completion -> entry when done with bad result: " 119 "~n Bad: ~p" 120 "~n Good: ~p", [Bad, Good]), 121 {error, Bad, Good}; 122await_completion(Pids, Bad, Good, Timeout) -> 123 print("await_completion -> entry when waiting for" 124 "~n Pids: ~p" 125 "~n Bad: ~p" 126 "~n Good: ~p" 127 "~n Timeout: ~p", [Pids, Bad, Good, Timeout]), 128 Begin = ms(), 129 receive 130 {'EXIT', Pid, {ok, FinalState}} -> 131 case lists:delete(Pid, Pids) of 132 Pids -> 133 print("await_completion -> " 134 "received ok EXIT signal from unknown ~p", [Pid]), 135 await_completion(Pids, Bad, Good, 136 Timeout - (ms() - Begin)); 137 Pids2 -> 138 print("await_completion -> success from ~p", [Pid]), 139 await_completion(Pids2, 140 Bad, 141 [{Pid, FinalState}|Good], 142 Timeout - (ms() - Begin)) 143 end; 144 145 {'EXIT', Pid, {error, Reason}} -> 146 case lists:delete(Pid, Pids) of 147 Pids -> 148 print("await_completion -> " 149 "received error EXIT signal from unknown ~p", [Pid]), 150 await_completion(Pids, Bad, Good, 151 Timeout - (ms() - Begin)); 152 Pids2 -> 153 print("await_completion -> failure from ~p", [Pid]), 154 await_completion(Pids2, 155 [{Pid, Reason}|Bad], 156 Good, 157 Timeout - (ms() - Begin)) 158 end; 159 160 {'EXIT', Pid, {skip, Reason}} -> 161 print("await_completion -> skip (exit) from ~p:" 162 " ~p", [Pid, Reason]), 163 ?SKIP(Reason) 164 165 after Timeout -> 166 print("await_completion -> timeout"), 167 exit({timeout, Pids}) 168 end. 169 170 171 172%% ------- Misc functions -------- 173 174print(F) -> 175 print(F, []). 176 177print(F, A) -> 178 print(get(sname), F, A). 179 180print(N, F, A) when is_list(N) -> 181 io:format("*** [~s] ~p ~s ***" 182 "~n " ++ F ++ "~n", 183 [?FTS(), self(), N | A]); 184print(_N, F, A) -> 185 io:format("*** [~s] ~p *** " 186 "~n " ++ F ++ "~n", 187 [?FTS(), self() | A]). 188 189 190ms() -> 191 erlang:monotonic_time(milli_seconds). 192 193 194