/lib/diameter/test/diameter_util.erl

https://github.com/blackberry/Erlang-OTP · Erlang · 188 lines · 104 code · 36 blank · 48 comment · 1 complexity · 156f80d0940485f34a89fd14022ce766 MD5 · raw file

  1. %%
  2. %% %CopyrightBegin%
  3. %%
  4. %% Copyright Ericsson AB 2010-2011. All Rights Reserved.
  5. %%
  6. %% The contents of this file are subject to the Erlang Public License,
  7. %% Version 1.1, (the "License"); you may not use this file except in
  8. %% compliance with the License. You should have received a copy of the
  9. %% Erlang Public License along with this software. If not, it can be
  10. %% retrieved online at http://www.erlang.org/.
  11. %%
  12. %% Software distributed under the License is distributed on an "AS IS"
  13. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. %% the License for the specific language governing rights and limitations
  15. %% under the License.
  16. %%
  17. %% %CopyrightEnd%
  18. %%
  19. -module(diameter_util).
  20. %%
  21. %% Utility functions.
  22. %%
  23. -export([consult/2,
  24. run/1,
  25. fold/3,
  26. foldl/3,
  27. scramble/1,
  28. write_priv/3,
  29. read_priv/2]).
  30. -define(L, atom_to_list).
  31. %% consult/2
  32. %%
  33. %% Extract info from the app/appup file (presumably) of the named
  34. %% application.
  35. consult(Name, Suf)
  36. when is_atom(Name), is_atom(Suf) ->
  37. case code:lib_dir(Name, ebin) of
  38. {error = E, Reason} ->
  39. {E, {Name, Reason}};
  40. Dir ->
  41. consult(filename:join([Dir, ?L(Name) ++ "." ++ ?L(Suf)]))
  42. end.
  43. consult(Path) ->
  44. case file:consult(Path) of
  45. {ok, Terms} ->
  46. Terms;
  47. {error, Reason} ->
  48. {error, {Path, Reason}}
  49. end.
  50. %% Name/Path in the return value distinguish the errors and allow for
  51. %% a useful badmatch.
  52. %% run/1
  53. %%
  54. %% Evaluate functions in parallel and return a list of those that
  55. %% failed to return. The fun takes a boolean (did the function return
  56. %% or not), the function that was evaluated, the return value or exit
  57. %% reason and the prevailing accumulator.
  58. run(L) ->
  59. fold(fun cons/4, [], L).
  60. cons(true, _, _, Acc) ->
  61. Acc;
  62. cons(false, F, RC, Acc) ->
  63. [{F, RC} | Acc].
  64. %% fold/3
  65. %%
  66. %% Parallel fold. Results are folded in the order received.
  67. fold(Fun, Acc0, L)
  68. when is_function(Fun, 4) ->
  69. Ref = make_ref(),
  70. %% Spawn a middleman to collect down messages from processes
  71. %% spawned for each function so as not to assume that all DOWN
  72. %% messages are ours.
  73. MRef = run1([fun fold/4, Ref, Fun, Acc0, L], Ref),
  74. {Ref, RC} = down(MRef),
  75. RC.
  76. fold(Ref, Fun, Acc0, L) ->
  77. recv(run(Ref, L), Ref, Fun, Acc0).
  78. run(Ref, L) ->
  79. [{run1(F, Ref), F} || F <- L].
  80. run1(F, Ref) ->
  81. {_, MRef} = spawn_monitor(fun() -> exit({Ref, eval(F)}) end),
  82. MRef.
  83. recv([], _, _, Acc) ->
  84. Acc;
  85. recv(L, Ref, Fun, Acc) ->
  86. {MRef, R} = down(),
  87. {MRef, F} = lists:keyfind(MRef, 1, L),
  88. recv(lists:keydelete(MRef, 1, L),
  89. Ref,
  90. Fun,
  91. acc(R, Ref, F, Fun, Acc)).
  92. acc({Ref, RC}, Ref, F, Fun, Acc) ->
  93. Fun(true, F, RC, Acc);
  94. acc(Reason, _, F, Fun, Acc) ->
  95. Fun(false, F, Reason, Acc).
  96. down(MRef) ->
  97. receive {'DOWN', MRef, process, _, Reason} -> Reason end.
  98. down() ->
  99. receive {'DOWN', MRef, process, _, Reason} -> {MRef, Reason} end.
  100. %% foldl/3
  101. %%
  102. %% Parallel fold. Results are folded in order of the function list.
  103. foldl(Fun, Acc0, L)
  104. when is_function(Fun, 4) ->
  105. Ref = make_ref(),
  106. recvl(run(Ref, L), Ref, Fun, Acc0).
  107. recvl([], _, _, Acc) ->
  108. Acc;
  109. recvl([{MRef, F} | L], Ref, Fun, Acc) ->
  110. R = down(MRef),
  111. recvl(L, Ref, Fun, acc(R, Ref, F, Fun, Acc)).
  112. %% scramble/1
  113. %%
  114. %% Sort a list into random order.
  115. scramble(L) ->
  116. foldl(fun(true, _, S, false) -> S end,
  117. false,
  118. [[fun s/1, L]]).
  119. s(L) ->
  120. random:seed(now()),
  121. s([], L).
  122. s(Acc, []) ->
  123. Acc;
  124. s(Acc, L) ->
  125. {H, [T|Rest]} = lists:split(random:uniform(length(L)) - 1, L),
  126. s([T|Acc], H ++ Rest).
  127. %% eval/1
  128. eval({M,[F|A]})
  129. when is_atom(F) ->
  130. apply(M,F,A);
  131. eval({M,F,A}) ->
  132. apply(M,F,A);
  133. eval([F|A])
  134. when is_function(F) ->
  135. apply(F,A);
  136. eval(L)
  137. when is_list(L) ->
  138. run(L);
  139. eval(F)
  140. when is_function(F,0) ->
  141. F().
  142. %% write_priv/3
  143. write_priv(Config, Name, Term) ->
  144. Dir = proplists:get_value(priv_dir, Config),
  145. Path = filename:join([Dir, Name]),
  146. ok = file:write_file(Path, term_to_binary(Term)).
  147. %% read_priv/2
  148. read_priv(Config, Name) ->
  149. Dir = proplists:get_value(priv_dir, Config),
  150. Path = filename:join([Dir, Name]),
  151. {ok, Bin} = file:read_file(Path),
  152. binary_to_term(Bin).