snmp_test_server.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 372 行
ERL
372 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%%%----------------------------------------------------------------------%% Purpose: Lightweight test server%%-----------------------------------------------------------------------module(snmp_test_server).-compile(export_all).-include("snmp_test_lib.hrl").-define(d(F,A),d(F,A,?LINE)).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Evaluates a test case or test suite%% Returns a list of failing test cases:%% %% {Mod, Fun, ExpectedRes, ActualRes}%%----------------------------------------------------------------------t(Case) -> io:format("~n", []), ?d("t(~p) -> entry", [Case]), Res = t(Case, default_config()), display_result(Res), Res;t([Mod, Fun]) when atom(Mod), atom(Fun) -> ?d("t([~w,~w]:1) -> entry", [Mod, Fun]), Res = t({Mod, Fun}, default_config()), display_result(Res), ?d("t(~p,~p) -> Res:~n~p", [Mod, Fun, Res]), Res. t({Mod, Fun}, Config) when atom(Mod), atom(Fun), list(Config) -> ?d("t(~p,~p) -> entry", [Mod, Fun]), case (catch apply(Mod, Fun, [suite])) of [] -> io:format("~n~n*** Eval: ~p ***************~n", [{Mod, Fun}]), case eval(Mod, Fun, Config) of {ok, _, _} -> []; Other -> [Other] end; Cases when list(Cases) -> io:format("~n*** Expand: ~p ...~n", [{Mod, Fun}]), Map = fun(Case) when atom(Case)-> {Mod, Case}; (Case) -> Case end, t(lists:map(Map, Cases), Config); {req, _, SubCases} when list(SubCases) -> do_subcases(Mod, Fun, SubCases, Config, []); {req, _, Conf} -> do_subcases(Mod, Fun, [Conf], Config, []); {'EXIT', {undef, _}} -> io:format("~n*** Undefined: ~p~n", [{Mod, Fun}]), [{nyi, {Mod, Fun}, ok}]; Error -> io:format("~n*** Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]), [{failed, {Mod, Fun}, Error}] end;t(Mod, Config) when atom(Mod), list(Config) -> ?d("t(~p) -> entry whith" "~n Config: ~p", [Mod, Config]), t({Mod, all}, Config);t(Cases, Config) when list(Cases), list(Config) -> ?d("t -> entry whith" "~n Cases: ~p" "~n Config: ~p", [Cases, Config]), Errors = [t(Case, Config) || Case <- Cases], ?d("t -> Errors: ~n~p", [Errors]), lists:append(Errors);t(Bad, Config) -> ?d("t -> entry with" "~n Bad: ~p" "~n Config: ~p", [Bad, Config]), [{badarg, Bad, ok}].do_case(M,F,C) -> io:format("~n~n*** Eval: ~p ***************~n", [{M, F}]), case eval(M, F, C) of {ok, _, _} -> []; Other -> [Other] end. do_subcases(_Mod, _Fun, [], _Config, Acc) -> ?d("t -> do_subcases([]) -> entry with" "~n Acc: ~p", [Acc]), lists:flatten(lists:reverse(Acc));do_subcases(Mod, Fun, [{conf, Init, Cases, Finish}|SubCases], Config, Acc) -> ?d("t -> do_subcases(conf) -> entry with" "~n Init: ~p" "~n Cases: ~p" "~n Finish: ~p", [Init, Cases, Finish]), R = case (catch apply(Mod, Init, [Config])) of Conf when list(Conf) -> io:format("~n*** Expand: ~p ...~n", [{Mod, Fun}]), Map = fun(Case) when atom(Case) -> {Mod, Case}; (Case) -> Case end, Res = t(lists:map(Map, Cases), Conf), (catch apply(Mod, Finish, [Conf])), Res; {'EXIT', {skipped, Reason}} -> io:format(" => skipping: ~p~n", [Reason]), [{skipped, {Mod, Fun}, Reason}]; Error -> io:format(" => init (~p) failed: ~n~p~n", [Init, Error]), (catch apply(Mod, Finish, [Config])), [{failed, {Mod, Fun}, Error}] end, ?d("t -> do_subcases(conf):" "~n R: ~p", [R]), do_subcases(Mod, Fun, SubCases, Config, [R|Acc]);do_subcases(Mod, Fun, [SubCase|SubCases], Config, Acc) when atom(SubCase) -> ?d("t -> do_subcases(~p)", [SubCase]), R = do_case(Mod, SubCase, Config), do_subcases(Mod, Fun, SubCases,Config, [R|Acc]).eval(Mod, Fun, Config) -> ?d("eval -> entry with" "~n Mod: ~p" "~n Fun: ~p", [Mod, Fun]), global:register_name(inets_test_case_sup, self()), Flag = process_flag(trap_exit, true), Config2 = Mod:init_per_testcase(Fun, Config), Pid = spawn_link(?MODULE, do_eval, [self(), Mod, Fun, Config2]), R = wait_for_evaluator(Pid, Mod, Fun, Config2, []), Mod:fin_per_testcase(Fun, Config2), global:unregister_name(inets_test_case_sup), process_flag(trap_exit, Flag), ?d("eval -> exit with:" "~n R: ~p", [R]), R.wait_for_evaluator(Pid, Mod, Fun, Config, Errors) -> Pre = lists:concat(["TEST CASE: ", Fun]), receive {'EXIT', _Watchdog, watchdog_timeout} -> io:format("*** ~s WATCHDOG TIMEOUT~n", [Pre]), exit(Pid, kill), {failed, {Mod,Fun}, watchdog_timeout}; {done, Pid, ok} when Errors == [] -> io:format("*** ~s OK~n", [Pre]), {ok, {Mod, Fun}, Errors}; {done, Pid, {ok, _}} when Errors == [] -> io:format("*** ~s OK~n", [Pre]), {ok, {Mod, Fun}, Errors}; {done, Pid, Fail} -> io:format("*** ~s FAILED~n~p~n", [Pre, Fail]), {failed, {Mod,Fun}, Fail}; {'EXIT', Pid, {skipped, Reason}} -> io:format("*** ~s SKIPPED~n~p~n", [Pre, Reason]), {skipped, {Mod, Fun}, Errors}; {'EXIT', Pid, Reason} -> io:format("*** ~s CRASHED~n~p~n", [Pre, Reason]), {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors]}; {fail, Pid, Reason} -> io:format("*** ~s FAILED~n~p~n", [Pre, Reason]), wait_for_evaluator(Pid, Mod, Fun, Config, Errors ++ [Reason]) end.do_eval(ReplyTo, Mod, Fun, Config) -> ?d("do_eval -> entry with" "~n ReplyTo: ~p" "~n Mod: ~p" "~n Fun: ~p" "~n Config: ~p" "~nat" "~n ~p", [ReplyTo, Mod, Fun, Config, erlang:now()]), case (catch apply(Mod, Fun, [Config])) of {'EXIT', {skipped, Reason}} -> ReplyTo ! {'EXIT', self(), {skipped, Reason}}; Other -> ?d("do_eval -> entry with" "~n Other: ~p", [Other]), ReplyTo ! {done, self(), Other} end, ?d("do_eval -> case ~p completed at ~p", [Fun, erlang:now()]), unlink(ReplyTo), exit(shutdown).display_result([]) -> io:format("TEST OK~n", []);display_result(Errors) when list(Errors) -> Nyi = [MF || {nyi, MF, _} <- Errors], Skipped = [{MF, Reason} || {skipped, MF, Reason} <- Errors], Crashed = [{MF, Reason} || {crashed, MF, Reason} <- Errors], Failed = [{MF, Reason} || {failed, MF, Reason} <- Errors], display_skipped(Skipped), display_crashed(Crashed), display_failed(Failed), display_summery(Nyi, Skipped, Crashed, Failed).display_summery(Nyi, Skipped, Crashed, Failed) -> io:format("~nTest case summery:~n", []), display_summery(Nyi, "not yet implemented"), display_summery(Skipped, "skipped"), display_summery(Crashed, "crashed"), display_summery(Failed, "failed"), io:format("~n", []). display_summery([], _) -> ok;display_summery(Res, Info) -> io:format(" ~w test cases ~s~n", [length(Res), Info]). display_skipped([]) -> io:format("Skipped test cases: -~n", []);display_skipped(Skipped) -> io:format("Skipped test cases:~n", []), [io:format(" ~p => ~p~n", [MF, Reason]) || {MF, Reason} <- Skipped], io:format("~n", []). display_crashed([]) -> io:format("Crashed test cases: -~n", []);display_crashed(Crashed) -> io:format("Crashed test cases:~n", []), [io:format(" ~p => ~p~n", [MF, Reason]) || {MF, Reason} <- Crashed], io:format("~n", []). display_failed([]) -> io:format("Failed test cases: -~n", []);display_failed(Failed) -> io:format("Failed test cases:~n", []), [io:format(" ~p => ~p~n", [MF, Reason]) || {MF, Reason} <- Failed], io:format("~n", []). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Verify that the actual result of a test case matches the exected one%% Returns the actual result%% Stores the result in the process dictionary if mismatcherror(Actual, Mod, Line) -> global:send(inets_global_logger, {failed, Mod, Line}), log("<ERROR> Bad result: ~p~n", [Actual], Mod, Line), case global:whereis_name(inets_test_case_sup) of undefined -> ignore; Pid -> Pid ! {fail, self(), {Actual, Mod, Line}} end, Actual.skip(Actual, Mod, Line) -> log("Skipping test case~n", [], Mod, Line), exit({skipped, {Actual, Mod, Line}}).fatal_skip(Actual, Mod, Line) -> ?d("fatal_skip -> entry with" "~n Actual: ~p" "~n Mod: ~p" "~n Line: ~p", [Actual, Mod, Line]), error(Actual, Mod, Line), exit(shutdown).log(Format, Args, Mod, Line) -> case global:whereis_name(inets_global_logger) of undefined -> io:format(user, "~p(~p): " ++ Format, [Mod, Line] ++ Args); Pid -> io:format(Pid, "~p(~p): " ++ Format, [Mod, Line] ++ Args) end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Test server callbacksinit_per_testcase(Case, Config) -> ?d("init_per_testcase(~p) -> entry", [Case]), global:register_name(megaco_global_logger, group_leader()), Config.fin_per_testcase(Case, Config) -> ?d("fin_per_testcase(~p) -> entry", [Case]), global:unregister_name(megaco_global_logger), ok.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Internal utility functionsdefault_config() -> [{nodes, default_nodes()}].default_nodes() -> mk_nodes(2, []).mk_nodes(0, Nodes) -> Nodes;mk_nodes(N, []) -> mk_nodes(N - 1, [node()]);mk_nodes(N, Nodes) when N > 0 -> Head = hd(Nodes), [Name, Host] = node_to_name_and_host(Head), Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)].mk_node(N, Name, Host) -> list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). %% Returns [Name, Host] node_to_name_and_host(Node) -> string:tokens(atom_to_list(Node), [$@]).start_nodes([Node | Nodes], File, Line) -> case net_adm:ping(Node) of pong -> start_nodes(Nodes, File, Line); pang -> [Name, Host] = node_to_name_and_host(Node), Args = [], case ?STARTL_NODE(Host, Name, Args) of {ok, NewNode} when NewNode == Node -> start_nodes(Nodes, File, Line); Other -> fatal_skip({cannot_start_node, Node, Other}, File, Line) end end;start_nodes([], File, Line) -> ok.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%d(F, A, L) -> %% d(true, F, A, L). d(get(dbg), F, A, L).d(true, F, A, L) -> io:format("STS:~p:~p " ++ F ++ "~n", [self(),L|A]);d(_, _, _, _) -> ok.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?