From c75c5a530c10158d4a586a372a165835835bba1b Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 22 Jul 2011 12:09:53 +0200 Subject: Add codec suite based on pure ct --- lib/diameter/test/diameter_util.erl | 170 ++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 lib/diameter/test/diameter_util.erl (limited to 'lib/diameter/test/diameter_util.erl') diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl new file mode 100644 index 0000000000..93760a1c07 --- /dev/null +++ b/lib/diameter/test/diameter_util.erl @@ -0,0 +1,170 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% 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 online 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. +%% +%% %CopyrightEnd% +%% + +-module(diameter_util). + +%% +%% Utility functions. +%% + +-export([appfile/1, + run/1, + fold/3, + foldl/3, + scramble/1, + ps/0]). + +%% appfile/1 +%% +%% Extract info from the app file of the named application. + +appfile(Name) -> + appfile(code:lib_dir(Name, ebin), Name). + +appfile({error = E, Reason}, _) -> + {E, {code, Reason}}; +appfile(Dir, Name) -> + case file:consult(filename:join([Dir, atom_to_list(Name) ++ ".app"])) of + {ok, [{application, Name, App}]} -> + {ok, App}; + {ok, Huh} -> + {error, {content, Huh}}; + {error, Reason} -> + {error, {file, Reason}} + end. + +%% run/1 +%% +%% Evaluate functions in parallel and return a list of those that +%% failed to return. The fun takes a boolean (did the function return +%% or not), the function that was evaluated, the return value or exit +%% reason and the prevailing accumulator. + +run(L) -> + fold(fun cons/4, [], L). + +cons(true, _, _, Acc) -> + Acc; +cons(false, F, RC, Acc) -> + [{F, RC} | Acc]. + +%% fold/3 +%% +%% Parallel fold. Results are folded in the order received. + +fold(Fun, Acc0, L) + when is_function(Fun, 4) -> + Ref = make_ref(), + %% Spawn a middleman to collect down messages from processes + %% spawned for each function so as not to assume that all DOWN + %% messages are ours. + MRef = run1([fun fold/4, Ref, Fun, Acc0, L], Ref), + {Ref, RC} = down(MRef), + RC. + +fold(Ref, Fun, Acc0, L) -> + recv(run(Ref, L), Ref, Fun, Acc0). + +run(Ref, L) -> + [{run1(F, Ref), F} || F <- L]. + +run1(F, Ref) -> + {_, MRef} = spawn_monitor(fun() -> exit({Ref, eval(F)}) end), + MRef. + +recv([], _, _, Acc) -> + Acc; +recv(L, Ref, Fun, Acc) -> + {MRef, R} = down(), + {MRef, F} = lists:keyfind(MRef, 1, L), + recv(lists:keydelete(MRef, 1, L), + Ref, + Fun, + acc(R, Ref, F, Fun, Acc)). + +acc({Ref, RC}, Ref, F, Fun, Acc) -> + Fun(true, F, RC, Acc); +acc(Reason, _, F, Fun, Acc) -> + Fun(false, F, Reason, Acc). + +down(MRef) -> + receive {'DOWN', MRef, process, _, Reason} -> Reason end. + +down() -> + receive {'DOWN', MRef, process, _, Reason} -> {MRef, Reason} end. + +%% foldl/3 +%% +%% Parallel fold. Results are folded in order of the function list. + +foldl(Fun, Acc0, L) + when is_function(Fun, 4) -> + Ref = make_ref(), + recvl(run(Ref, L), Ref, Fun, Acc0). + +recvl([], _, _, Acc) -> + Acc; +recvl([{MRef, F} | L], Ref, Fun, Acc) -> + R = down(MRef), + recvl(L, Ref, Fun, acc(R, Ref, F, Fun, Acc)). + +%% scramble/1 +%% +%% Sort a list into random order. + +scramble(L) -> + foldl(fun(true, _, S, false) -> S end, + false, + [[fun s/1, L]]). + +s(L) -> + random:seed(now()), + s([], L). + +s(Acc, []) -> + Acc; +s(Acc, L) -> + {H, [T|Rest]} = lists:split(random:uniform(length(L)) - 1, L), + s([T|Acc], H ++ Rest). + +%% ps/0 + +ps() -> + [{P, process_info(P)} || P <- erlang:processes()]. + +%% eval/1 + +eval({M,[F|A]}) + when is_atom(F) -> + apply(M,F,A); + +eval({M,F,A}) -> + apply(M,F,A); + +eval([F|A]) + when is_function(F) -> + apply(F,A); + +eval(L) + when is_list(L) -> + run(L); + +eval(F) + when is_function(F,0) -> + F(). -- cgit v1.2.3 From c70314ecb08697d0926c0e86e048cd22dab60068 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 27 Jul 2011 19:26:57 +0200 Subject: Move appup tests into app suite and use systools for both --- lib/diameter/test/diameter_util.erl | 39 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'lib/diameter/test/diameter_util.erl') diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 93760a1c07..99f4fa1977 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -23,31 +23,38 @@ %% Utility functions. %% --export([appfile/1, +-export([consult/2, run/1, fold/3, foldl/3, scramble/1, ps/0]). -%% appfile/1 +-define(L, atom_to_list). + +%% consult/2 %% -%% Extract info from the app file of the named application. - -appfile(Name) -> - appfile(code:lib_dir(Name, ebin), Name). - -appfile({error = E, Reason}, _) -> - {E, {code, Reason}}; -appfile(Dir, Name) -> - case file:consult(filename:join([Dir, atom_to_list(Name) ++ ".app"])) of - {ok, [{application, Name, App}]} -> - {ok, App}; - {ok, Huh} -> - {error, {content, Huh}}; +%% Extract info from the app/appup file (presumably) of the named +%% application. + +consult(Name, Suf) + when is_atom(Name), is_atom(Suf) -> + case code:lib_dir(Name, ebin) of + {error = E, Reason} -> + {E, {Name, Reason}}; + Dir -> + consult(filename:join([Dir, ?L(Name) ++ "." ++ ?L(Suf)])) + end. + +consult(Path) -> + case file:consult(Path) of + {ok, Terms} -> + Terms; {error, Reason} -> - {error, {file, Reason}} + {error, {Path, Reason}} end. +%% Name/Path in the return value distinguish the errors and allow for +%% a useful badmatch. %% run/1 %% -- cgit v1.2.3