gproc_dist_tests.erl 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. %% ``The contents of this file are subject to the Erlang Public License,
  2. %% Version 1.1, (the "License"); you may not use this file except in
  3. %% compliance with the License. You should have received a copy of the
  4. %% Erlang Public License along with this software. If not, it can be
  5. %% retrieved via the world wide web at http://www.erlang.org/.
  6. %%
  7. %% Software distributed under the License is distributed on an "AS IS"
  8. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  9. %% the License for the specific language governing rights and limitations
  10. %% under the License.
  11. %%
  12. %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  13. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  14. %% AB. All Rights Reserved.''
  15. %%
  16. %% @author Ulf Wiger <ulf.wiger@erlang-solutions.com>
  17. %%
  18. -module(gproc_dist_tests).
  19. -ifdef(TEST).
  20. -include_lib("eunit/include/eunit.hrl").
  21. -export([t_spawn/1, t_spawn_reg/2]).
  22. dist_test_() ->
  23. {timeout, 120,
  24. [{setup,
  25. fun() ->
  26. Ns = start_slaves([dist_test_n1, dist_test_n2]),
  27. ?assertMatch({[ok,ok],[]},
  28. rpc:multicall(Ns, application, start, [gproc])),
  29. %% ?debugVal(Ns)
  30. Ns
  31. end,
  32. fun(Ns) ->
  33. [rpc:call(N, init, stop, []) || N <- Ns]
  34. end,
  35. fun(Ns) ->
  36. {inorder,
  37. [
  38. {inparallel, [
  39. fun() ->
  40. ?debugVal(t_simple_reg(Ns))
  41. end,
  42. fun() ->
  43. ?debugVal(t_mreg(Ns))
  44. end,
  45. fun() ->
  46. ?debugVal(t_await_reg(Ns))
  47. end,
  48. fun() ->
  49. ?debugVal(t_await_reg_exists(Ns))
  50. end,
  51. fun() ->
  52. ?debugVal(t_give_away(Ns))
  53. end,
  54. fun() ->
  55. ?debugVal(t_sync(Ns))
  56. end
  57. ]
  58. },
  59. {timeout, 90, [fun() ->
  60. ?debugVal(t_fail_node(Ns))
  61. end]}
  62. ]}
  63. end
  64. }]}.
  65. -define(T_NAME, {n, g, {?MODULE, ?LINE}}).
  66. -define(T_KVL, [{foo, "foo"}, {bar, "bar"}]).
  67. t_simple_reg([H|_] = Ns) ->
  68. Name = ?T_NAME,
  69. P = t_spawn_reg(H, Name),
  70. ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P)),
  71. ?assertMatch(true, t_call(P, {apply, gproc, unreg, [Name]})),
  72. ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
  73. ?assertMatch(ok, t_call(P, die)).
  74. t_mreg([H|_]) ->
  75. Kvl = ?T_KVL,
  76. P = t_spawn_mreg(H, Kvl),
  77. ?assertMatch(ok, t_call(P, die)).
  78. t_await_reg([A,B|_]) ->
  79. Name = ?T_NAME,
  80. P = t_spawn(A),
  81. Ref = erlang:monitor(process, P),
  82. P ! {self(), Ref, {apply, gproc, await, [Name]}},
  83. t_sleep(),
  84. P1 = t_spawn_reg(B, Name),
  85. ?assert(P1 == receive
  86. {P, Ref, Res} ->
  87. element(1, Res);
  88. {'DOWN', Ref, _, _, Reason} ->
  89. erlang:error(Reason);
  90. Other ->
  91. erlang:error({received,Other})
  92. end),
  93. ?assertMatch(ok, t_call(P, die)),
  94. ?assertMatch(ok, t_call(P1, die)).
  95. t_await_reg_exists([A,B|_]) ->
  96. Name = ?T_NAME,
  97. P = t_spawn(A),
  98. Ref = erlang:monitor(process, P),
  99. P1 = t_spawn_reg(B, Name),
  100. P ! {self(), Ref, {apply, gproc, await, [Name]}},
  101. ?assert(P1 == receive
  102. {P, Ref, Res} ->
  103. element(1, Res);
  104. {'DOWN', Ref, _, _, Reason} ->
  105. erlang:error(Reason);
  106. Other ->
  107. erlang:error({received,Other})
  108. end),
  109. ?assertMatch(ok, t_call(P, die)),
  110. ?assertMatch(ok, t_call(P1, die)).
  111. t_give_away([A,B|_] = Ns) ->
  112. Na = ?T_NAME,
  113. Nb = ?T_NAME,
  114. Pa = t_spawn_reg(A, Na),
  115. Pb = t_spawn_reg(B, Nb),
  116. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
  117. ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
  118. ?assertMatch(Pb, t_call(Pa, {apply, gproc, give_away, [Na, Nb]})),
  119. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pb)),
  120. ?assertMatch(Pa, t_call(Pb, {apply, gproc, give_away, [Na, Pa]})),
  121. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
  122. ?assertMatch(ok, t_call(Pa, die)),
  123. ?assertMatch(ok, t_call(Pb, die)).
  124. t_sync(Ns) ->
  125. %% Don't really know how to test this...
  126. [?assertMatch(true, rpc:call(N, gproc_dist, sync, []))
  127. || N <- Ns].
  128. t_fail_node([A,B|_] = Ns) ->
  129. Na = ?T_NAME,
  130. Nb = ?T_NAME,
  131. Pa = t_spawn_reg(A, Na),
  132. Pb = t_spawn_reg(B, Nb),
  133. ?assertMatch(ok, rpc:call(A, application, stop, [gproc])),
  134. ?assertMatch(ok, t_lookup_everywhere(Na, Ns -- [A], undefined)),
  135. ?assertMatch(ok, t_lookup_everywhere(Nb, Ns -- [A], Pb)),
  136. ?assertMatch(ok, rpc:call(A, application, start, [gproc])),
  137. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, undefined)),
  138. ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
  139. ?assertMatch(ok, t_call(Pa, die)),
  140. ?assertMatch(ok, t_call(Pb, die)).
  141. t_sleep() ->
  142. timer:sleep(500).
  143. t_lookup_everywhere(Key, Nodes, Exp) ->
  144. t_lookup_everywhere(Key, Nodes, Exp, 3).
  145. t_lookup_everywhere(Key, _, Exp, 0) ->
  146. {lookup_failed, Key, Exp};
  147. t_lookup_everywhere(Key, Nodes, Exp, I) ->
  148. Expected = [{N, Exp} || N <- Nodes],
  149. Found = [{N,rpc:call(N, gproc, where, [Key])} || N <- Nodes],
  150. if Expected =/= Found ->
  151. ?debugFmt("lookup ~p failed (~p), retrying...~n", [Key, Found]),
  152. t_sleep(),
  153. t_lookup_everywhere(Key, Nodes, Exp, I-1);
  154. true ->
  155. ok
  156. end.
  157. t_spawn(Node) ->
  158. Me = self(),
  159. P = spawn(Node, fun() ->
  160. Me ! {self(), ok},
  161. t_loop()
  162. end),
  163. receive
  164. {P, ok} -> P
  165. end.
  166. t_spawn_reg(Node, Name) ->
  167. Me = self(),
  168. spawn(Node, fun() ->
  169. ?assertMatch(true, gproc:reg(Name)),
  170. Me ! {self(), ok},
  171. t_loop()
  172. end),
  173. receive
  174. {P, ok} -> P
  175. end.
  176. t_spawn_mreg(Node, KVL) ->
  177. Me = self(),
  178. spawn(Node, fun() ->
  179. ?assertMatch(true, gproc:mreg(p, g, KVL)),
  180. Me ! {self(), ok},
  181. t_loop()
  182. end),
  183. receive
  184. {P, ok} -> P
  185. end.
  186. t_call(P, Req) ->
  187. Ref = erlang:monitor(process, P),
  188. P ! {self(), Ref, Req},
  189. receive
  190. {P, Ref, Res} ->
  191. erlang:demonitor(Ref),
  192. Res;
  193. {'DOWN', Ref, _, _, Error} ->
  194. erlang:error({'DOWN', P, Error})
  195. end.
  196. t_loop() ->
  197. receive
  198. {From, Ref, die} ->
  199. From ! {self(), Ref, ok};
  200. {From, Ref, {apply, M, F, A}} ->
  201. From ! {self(), Ref, apply(M, F, A)},
  202. t_loop();
  203. Other ->
  204. ?debugFmt("got unknown msg: ~p~n", [Other]),
  205. exit({unknown_msg, Other})
  206. end.
  207. start_slaves(Ns) ->
  208. [H|T] = Nodes = [start_slave(N) || N <- Ns],
  209. _ = [rpc:call(H, net, ping, [N]) || N <- T],
  210. Nodes.
  211. start_slave(Name) ->
  212. case node() of
  213. nonode@nohost ->
  214. os:cmd("epmd -daemon"),
  215. {ok, _} = net_kernel:start([gproc_master, longnames]);
  216. _ ->
  217. ok
  218. end,
  219. {ok, Node} = slave:start(
  220. host(), Name,
  221. "-pa . -pz ../ebin -pa ../deps/gen_leader/ebin "
  222. "-gproc gproc_dist all"),
  223. %% io:fwrite(user, "Slave node: ~p~n", [Node]),
  224. Node.
  225. host() ->
  226. [_Name, Host] = re:split(atom_to_list(node()), "@", [{return, list}]),
  227. list_to_atom(Host).
  228. -endif.