diff options
Diffstat (limited to 'lib/megaco/test/megaco_test_lib.erl')
-rw-r--r-- | lib/megaco/test/megaco_test_lib.erl | 349 |
1 files changed, 190 insertions, 159 deletions
diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl index 55eee97443..f64743f32a 100644 --- a/lib/megaco/test/megaco_test_lib.erl +++ b/lib/megaco/test/megaco_test_lib.erl @@ -112,101 +112,17 @@ os_based_skip(_) -> %% {Mod, Fun, ExpectedRes, ActualRes} %%---------------------------------------------------------------------- -tickets(Case) -> - Res = lists:flatten(tickets(Case, default_config())), - %% io:format("~w:tickets(Case = ~w) -> Res: ~p~n", [?MODULE, Case, Res]), +tickets([Mod]) -> + tickets(Mod); +tickets(Mod) when is_atom(Mod) -> + %% p("tickets -> entry with" + %% "~n Mod: ~p", [Mod]), + Res0 = t({Mod, {group, tickets}, Mod:groups()}, default_config()), + Res = lists:flatten(Res0), + %% p("tickets(~w) -> Res: ~p~n", [Mod, Res]), display_result(Res), Res. -tickets(Cases, Config) when is_list(Cases) -> - [tickets(Case, Config) || Case <- Cases]; -tickets(Mod, Config) when is_atom(Mod) -> - Res = tickets(Mod, tickets, Config), - %% io:format("~w:tickets(Mod = ~w) -> Res: ~p~n", [?MODULE, Mod, Res]), - Res; -tickets(Bad, _Config) -> - [{badarg, Bad, ok}]. - -tickets(Mod, Func, Config) -> - %% io:format("~w:tickets -> entry with" - %% "~n Mod: ~p" - %% "~n Func: ~p" - %% "~n Config: ~p" - %% "~n", [?MODULE, Mod, Func, Config]), - case (catch Mod:Func(suite)) of - [] -> - io:format("Eval: ~p:", [{Mod, Func}]), - Res = eval(Mod, Func, Config), - %% io:format("~w:tickets -> evaluated" - %% "~n Res: ~p" - %% "~n", [?MODULE, Res]), - {R, _, _, _} = Res, - io:format(" ~p~n", [R]), - Res; - - Cases when is_list(Cases) -> - io:format("Expand: ~p:~p ... ~n" - " ~p~n", [Mod, Func, Cases]), - Map = fun({M,_}) when is_atom(M) -> - tickets(M, tickets, Config); - (F) when is_atom(F) -> - tickets(Mod, F, Config); - (Case) -> Case - end, - lists:map(Map, Cases); - - {req, _, {conf, Init, Cases, Finish}} -> - %% io:format("~w:tickets -> suite result req-conf: " - %% "~n Init: ~p" - %% "~n Cases: ~p" - %% "~n Finish: ~p" - %% "~n", [?MODULE, Init, Cases, Finish]), - case (catch Mod:Init(Config)) of - Conf when is_list(Conf) -> - io:format("Expand: ~p:~p ...~n", [Mod, Func]), - Map = fun({M,_}) when is_atom(M) -> - %% io:format("~w:tickets -> " - %% "~n M: ~p" - %% "~n", [?MODULE, M]), - tickets(M, tickets, Conf); - (F) when is_atom(F) -> - %% io:format("~w:tickets -> " - %% "~n F: ~p" - %% "~n", [?MODULE, F]), - tickets(Mod, F, Conf); - (Case) -> - %% io:format("~w:tickets -> " - %% "~n Case: ~p" - %% "~n", [?MODULE, Case]), - Case - end, - Res = lists:map(Map, Cases), - %% io:format("~w:tickets -> and now finish when: " - %% "~n Res: ~p" - %% "~n", [?MODULE, Res]), - (catch Mod:Finish(Conf)), - %% io:format("~w:tickets -> finished" - %% "~n", [?MODULE]), - Res; - - {'EXIT', {skipped, Reason}} -> - io:format(" => skipping: ~p~n", [Reason]), - [{skipped, {Mod, Func}, Reason}]; - - Error -> - io:format(" => init failed: ~p~n", [Error]), - [{failed, {Mod, Func}, Error}] - end; - - {'EXIT', {undef, _}} -> - io:format("Undefined: ~p~n", [{Mod, Func}]), - [{nyi, {Mod, Func}, ok}]; - - Error -> - io:format("Ignoring: ~p:~p: ~p~n", [Mod, Func, Error]), - [{failed, {Mod, Func}, Error}] - end. - display_alloc_info() -> io:format("Allocator memory information:~n", []), @@ -281,7 +197,13 @@ alloc_instance_mem_info(Key, InstanceInfo) -> end. +t([Case]) when is_atom(Case) -> + %% p("t -> entry with" + %% "~n [Case]: [~p]", [Case]), + t(Case); t(Case) -> + %% p("t -> entry with" + %% "~n Case: ~p", [Case]), process_flag(trap_exit, true), MEM = fun() -> case (catch erlang:memory()) of {'EXIT', _} -> @@ -295,12 +217,66 @@ t(Case) -> Res = lists:flatten(t(Case, default_config())), Alloc2 = alloc_info(), Mem2 = MEM(), - %% io:format("Res: ~p~n", [Res]), display_result(Res, Alloc1, Mem1, Alloc2, Mem2), Res. -t({Mod, Fun}, Config) when is_atom(Mod) andalso is_atom(Fun) -> - case catch apply(Mod, Fun, [suite]) of + +groups(Mod) when is_atom(Mod) -> + try Mod:groups() of + Groups when is_list(Groups) -> + Groups; + BadGroups -> + exit({bad_groups, Mod, BadGroups}) + catch + _:_ -> + [] + end. + +init_suite(Mod, Config) -> + Mod:init_per_suite(Config). + +end_suite(Mod, Config) -> + Mod:end_per_suite(Config). + +init_group(Mod, Group, Config) -> + Mod:init_per_group(Group, Config). + +end_group(Mod, Group, Config) -> + Mod:init_per_group(Group, Config). + +%% This is for sub-SUITEs +t({_Mod, {NewMod, all}, _Groups}, _Config) when is_atom(NewMod) -> + t(NewMod); +t({Mod, {group, Name} = Group, Groups}, Config) + when is_atom(Mod) andalso is_atom(Name) andalso is_list(Groups) -> + case lists:keysearch(Name, 1, Groups) of + {value, {Name, _Props, GroupsAndCases}} -> + try init_group(Mod, Name, Config) of + Config2 when is_list(Config2) -> + Res = [t({Mod, Case, Groups}, Config2) || + Case <- GroupsAndCases], + (catch end_group(Mod, Name, Config2)), + Res; + Error -> + io:format(" => group (~w) init failed: ~p~n", + [Name, Error]), + [{failed, {Mod, Group}, Error}] + catch + exit:{skipped, SkipReason} -> + io:format(" => skipping group: ~p~n", [SkipReason]), + [{skipped, {Mod, Group}, SkipReason, 0}]; + error:undef -> + [t({Mod, Case, Groups}, Config) || + Case <- GroupsAndCases]; + T:E -> + [{failed, {Mod, Group}, {T,E}, 0}] + end; + false -> + exit({unknown_group, Mod, Name, Groups}) + end; +t({Mod, Fun, _}, Config) + when is_atom(Mod) andalso is_atom(Fun) -> + try apply(Mod, Fun, [suite]) of [] -> io:format("Eval: ~p:", [{Mod, Fun}]), Res = eval(Mod, Fun, Config), @@ -315,39 +291,57 @@ t({Mod, Fun}, Config) when is_atom(Mod) andalso is_atom(Fun) -> end, t(lists:map(Map, Cases), Config); - {req, _, {conf, Init, Cases, Finish}} -> - case (catch apply(Mod, Init, [Config])) of - Conf when is_list(Conf) -> - io:format("Expand: ~p ...~n", [{Mod, Fun}]), - Map = fun(Case) when is_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, 0}]; - - Error -> - io:format(" => failed: ~p~n", [Error]), - [{failed, {Mod, Fun}, Error, 0}] - end; - - {'EXIT', {undef, _}} -> - io:format("Undefined: ~p~n", [{Mod, Fun}]), - [{nyi, {Mod, Fun}, ok, 0}]; - Error -> io:format("Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]), [{failed, {Mod, Fun}, Error, 0}] + + catch + error:undef -> + io:format("Undefined: ~p~n", [{Mod, Fun}]), + [{nyi, {Mod, Fun}, ok, 0}] + + end; t(Mod, Config) when is_atom(Mod) -> - Res = t({Mod, all}, Config), - Res; -t(Cases, Config) when is_list(Cases) -> - [t(Case, Config) || Case <- Cases]; + %% p("t -> entry with" + %% "~n Mod: ~p" + %% "~n Config: ~p", [Mod, Config]), + %% This is assumed to be a test suite, so we start by calling + %% the top test suite function(s) (all/0 and groups/0). + try Mod:all() of + Cases when is_list(Cases) -> + %% The list may contain atoms (actual test cases) and + %% group-tuples (a tuple naming a group of test cases). + %% A group is defined by the (optional) groups/0 function. + Groups = groups(Mod), + try init_suite(Mod, Config) of + Config2 when is_list(Config2) -> + Res = [t({Mod, Case, Groups}, Config2) || Case <- Cases], + (catch end_suite(Mod, Config2)), + Res; + Error -> + io:format(" => suite init failed: ~p~n", [Error]), + [{failed, {Mod, init_per_suite}, Error}] + catch + exit:{skipped, SkipReason} -> + io:format(" => skipping suite: ~p~n", [SkipReason]), + [{skipped, {Mod, init_per_suite}, SkipReason, 0}]; + error:undef -> + [t({Mod, Case, Groups}, Config) || Case <- Cases]; + T:E -> + io:format(" => failed suite: ~p~n", [{T,E}]), + [{failed, {Mod, init_per_suite}, {T,E}, 0}] + end; + + Crap -> + Crap + + catch + error:undef -> + io:format("Undefined: ~p~n", [{Mod, all}]), + [{nyi, {Mod, all}, ok, 0}] + + end; t(Bad, _Config) -> [{badarg, Bad, ok, 0}]. @@ -362,7 +356,7 @@ eval(Mod, Fun, Config) -> 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), + Mod:end_per_testcase(Fun, Config2), erase(megaco_test_server), global:unregister_name(megaco_test_case_sup), process_flag(trap_exit, Flag), @@ -411,15 +405,24 @@ wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) -> do_eval(ReplyTo, Mod, Fun, Config) -> display_system_info("before", Mod, Fun), - case timer:tc(Mod, Fun, [Config]) of - {Time, {'EXIT', {skipped, Reason}}} -> - display_tc_time(Time), - display_system_info("after (skipped)", Mod, Fun), - ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time}; - {Time, Other} -> + T1 = os:timestamp(), + try Mod:Fun(Config) of + Res -> + T2 = os:timestamp(), + Time = timer:now_diff(T2, T1), display_tc_time(Time), display_system_info("after", Mod, Fun), - ReplyTo ! {done, self(), Other, Time} + ReplyTo ! {done, self(), Res, Time} + catch + error:undef -> + ReplyTo ! {'EXIT', self(), undef, 0}; + exit:{skipped, Reason} -> + T2 = os:timestamp(), + Time = timer:now_diff(T2, T1), + display_tc_time(Time), + display_system_info("after (skipped)", Mod, Fun), + ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time} + end, unlink(ReplyTo), exit(shutdown). @@ -524,28 +527,56 @@ do_display_memory([{Key, Mem1}|MemInfo1], MemInfo2) -> display_result([]) -> io:format("OK~n", []); display_result(Res) when is_list(Res) -> - Ok = [{MF, Time} || {ok, MF, _, Time} <- Res], - Nyi = [MF || {nyi, MF, _, _Time} <- Res], - Skipped = [{MF, Reason} || {skipped, MF, Reason, _Time} <- Res], - Failed = [{MF, Reason} || {failed, MF, Reason, _Time} <- Res], - Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res], - display_summery(Ok, Nyi, Skipped, Failed, Crashed), + Ok = [{MF, Time} || {ok, MF, _, Time} <- Res], + Nyi = [MF || {nyi, MF, _, _Time} <- Res], + SkippedGrps = [{{M,G}, Reason} || + {skipped, {M, {group, G}}, Reason, _Time} <- Res], + SkippedCases = [{MF, Reason} || + {skipped, {_M, F} = MF, Reason, _Time} <- Res, + is_atom(F)], + FailedGrps = [{{M,G}, Reason} || + {failed, {M, {group, G}}, Reason, _Time} <- Res], + FailedCases = [{MF, Reason} || + {failed, {_M, F} = MF, Reason, _Time} <- Res, + is_atom(F)], + Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res], + display_summery(Ok, Nyi, + SkippedGrps, SkippedCases, + FailedGrps, FailedCases, + Crashed), display_ok(Ok), - display_skipped(Skipped), - display_failed(Failed), + display_skipped("groups", SkippedGrps), + display_skipped("test cases", SkippedCases), + display_failed("groups", FailedGrps), + display_failed("test cases", FailedCases), display_crashed(Crashed). -display_summery(Ok, Nyi, Skipped, Failed, Crashed) -> +display_summery(Ok, Nyi, + SkippedGrps, SkippedCases, + FailedGrps, FailedCases, + Crashed) -> io:format("~nTest case summery:~n", []), - display_summery(Ok, "successfull"), - display_summery(Nyi, "not yet implemented"), - display_summery(Skipped, "skipped"), - display_summery(Failed, "failed"), - display_summery(Crashed, "crashed"), + display_summery(Ok, "test case", "successfull"), + display_summery(Nyi, "test case", "not yet implemented"), + display_summery(SkippedGrps, "group", "skipped"), + display_summery(SkippedCases, "test case", "skipped"), + display_summery(FailedGrps, "group", "failed"), + display_summery(FailedCases, "test case", "failed"), + display_summery(Crashed, "test case", "crashed"), io:format("~n", []). -display_summery(Res, Info) -> - io:format(" ~w test cases ~s~n", [length(Res), Info]). + +display_summery(Res, Kind, Info) -> + Len = length(Res), + if + Len =:= 1 -> + display_summery(Len, Kind ++ " " ++ Info); + true -> + display_summery(Len, Kind ++ "s " ++ Info) + end. + +display_summery(Len, Info) -> + io:format(" ~w ~s~n", [Len, Info]). display_ok([]) -> ok; @@ -557,20 +588,20 @@ display_ok(Ok) -> lists:foreach(F, Ok), io:format("~n", []). -display_skipped([]) -> +display_skipped(_, []) -> ok; -display_skipped(Skipped) -> - io:format("Skipped test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, +display_skipped(Pre, Skipped) -> + io:format("Skipped ~s:~n", [Pre]), + F = fun({X, Reason}) -> io:format(" ~p => ~p~n", [X, Reason]) end, lists:foreach(F, Skipped), io:format("~n", []). -display_failed([]) -> +display_failed(_, []) -> ok; -display_failed(Failed) -> - io:format("Failed test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, +display_failed(Pre, Failed) -> + io:format("Failed ~s:~n", [Pre]), + F = fun({X, Reason}) -> io:format(" ~p => ~p~n", [X, Reason]) end, lists:foreach(F, Failed), io:format("~n", []). @@ -706,11 +737,11 @@ init_per_testcase(_Case, Config) -> end, set_kill_timer(Config). -fin_per_testcase(_Case, Config) -> +end_per_testcase(_Case, Config) -> Name = megaco_global_logger, case global:whereis_name(Name) of undefined -> - io:format("~w:fin_per_testcase -> already un-registered~n", + io:format("~w:end_per_testcase -> already un-registered~n", [?MODULE]), ok; Pid when is_pid(Pid) -> @@ -866,5 +897,5 @@ start_nodes([Node | Nodes], File, Line) -> start_nodes([], _File, _Line) -> ok. -p(F,A) -> - io:format("~p" ++ F ++ "~n", [self()|A]). +p(F, A) -> + io:format("~p~w:" ++ F ++ "~n", [self(), ?MODULE |A]). |