gproc_tests.erl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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_tests).
  19. -ifdef(TEST).
  20. -include_lib("eunit/include/eunit.hrl").
  21. -include_lib("stdlib/include/qlc.hrl").
  22. reg_test_() ->
  23. {setup,
  24. fun() ->
  25. application:start(gproc)
  26. end,
  27. fun(_) ->
  28. application:stop(gproc)
  29. end,
  30. [
  31. {spawn, ?_test(t_simple_reg())}
  32. , ?_test(t_is_clean())
  33. , {spawn, ?_test(t_simple_prop())}
  34. , ?_test(t_is_clean())
  35. , {spawn, ?_test(t_await())}
  36. , ?_test(t_is_clean())
  37. , {spawn, ?_test(t_simple_mreg())}
  38. , ?_test(t_is_clean())
  39. , {spawn, ?_test(t_gproc_crash())}
  40. , ?_test(t_is_clean())
  41. , {spawn, ?_test(t_cancel_wait_and_register())}
  42. , ?_test(t_is_clean())
  43. , {spawn, ?_test(t_give_away_to_pid())}
  44. , ?_test(t_is_clean())
  45. , {spawn, ?_test(t_give_away_to_self())}
  46. , ?_test(t_is_clean())
  47. , {spawn, ?_test(t_give_away_badarg())}
  48. , ?_test(t_is_clean())
  49. , {spawn, ?_test(t_give_away_to_unknown())}
  50. , ?_test(t_is_clean())
  51. , {spawn, ?_test(t_give_away_and_back())}
  52. , ?_test(t_is_clean())
  53. , {spawn, ?_test(t_select())}
  54. , ?_test(t_is_clean())
  55. , {spawn, ?_test(t_qlc())}
  56. , ?_test(t_is_clean())
  57. , {spawn, ?_test(t_get_env())}
  58. , ?_test(t_is_clean())
  59. , {spawn, ?_test(t_get_set_env())}
  60. , ?_test(t_is_clean())
  61. , {spawn, ?_test(t_set_env())}
  62. , ?_test(t_is_clean())
  63. ]}.
  64. t_simple_reg() ->
  65. ?assert(gproc:reg({n,l,name}) =:= true),
  66. ?assert(gproc:where({n,l,name}) =:= self()),
  67. ?assert(gproc:unreg({n,l,name}) =:= true),
  68. ?assert(gproc:where({n,l,name}) =:= undefined).
  69. t_simple_prop() ->
  70. ?assert(gproc:reg({p,l,prop}) =:= true),
  71. ?assert(t_other_proc(fun() ->
  72. ?assert(gproc:reg({p,l,prop}) =:= true)
  73. end) =:= ok),
  74. ?assert(gproc:unreg({p,l,prop}) =:= true).
  75. t_other_proc(F) ->
  76. {_Pid,Ref} = spawn_monitor(fun() -> exit(F()) end),
  77. receive
  78. {'DOWN',Ref,_,_,R} ->
  79. R
  80. after 10000 ->
  81. erlang:error(timeout)
  82. end.
  83. t_await() ->
  84. Me = self(),
  85. {_Pid,Ref} = spawn_monitor(
  86. fun() -> exit(?assert(gproc:await({n,l,t_await}) =:= {Me,val})) end),
  87. ?assert(gproc:reg({n,l,t_await},val) =:= true),
  88. receive
  89. {'DOWN', Ref, _, _, R} ->
  90. ?assertEqual(R, ok)
  91. after 10000 ->
  92. erlang:error(timeout)
  93. end.
  94. t_is_clean() ->
  95. sys:get_status(gproc), % in order to synch
  96. T = ets:tab2list(gproc),
  97. ?assert(T =:= []).
  98. t_simple_mreg() ->
  99. P = self(),
  100. ?assertEqual(true, gproc:mreg(n, l, [{foo, foo_val},
  101. {bar, bar_val}])),
  102. ?assertEqual(P, gproc:where({n,l,foo})),
  103. ?assertEqual(P, gproc:where({n,l,bar})).
  104. t_gproc_crash() ->
  105. P = spawn_helper(),
  106. ?assert(gproc:where({n,l,P}) =:= P),
  107. exit(whereis(gproc), kill),
  108. give_gproc_some_time(100),
  109. ?assert(whereis(gproc) =/= undefined),
  110. %%
  111. %% Check that the registration is still there using an ets:lookup(),
  112. %% Once we've killed the process, gproc will always return undefined
  113. %% if the process is not alive, regardless of whether the registration
  114. %% is still there. So, here, the lookup should find something...
  115. %%
  116. ?assert(ets:lookup(gproc,{{n,l,P},n}) =/= []),
  117. ?assert(gproc:where({n,l,P}) =:= P),
  118. exit(P, kill),
  119. %% ...and here, it shouldn't.
  120. %% (sleep for a while first to let gproc handle the EXIT
  121. give_gproc_some_time(10),
  122. ?assert(ets:lookup(gproc,{{n,l,P},n}) =:= []).
  123. t_cancel_wait_and_register() ->
  124. Alias = {n, l, foo},
  125. Me = self(),
  126. P = spawn(fun() ->
  127. {'EXIT',_} = (catch gproc:await(Alias, 100)),
  128. ?assert(element(1,sys:get_status(gproc)) == status),
  129. Me ! {self(), go_ahead},
  130. timer:sleep(infinity)
  131. end),
  132. receive
  133. {P, go_ahead} ->
  134. ?assertEqual(gproc:reg(Alias, undefined), true),
  135. exit(P, kill),
  136. timer:sleep(500),
  137. ?assert(element(1,sys:get_status(gproc)) == status)
  138. end.
  139. t_give_away_to_pid() ->
  140. From = {n, l, foo},
  141. Me = self(),
  142. P = spawn_link(fun t_loop/0),
  143. ?assertEqual(true, gproc:reg(From, undefined)),
  144. ?assertEqual(Me, gproc:where(From)),
  145. ?assertEqual(P, gproc:give_away(From, P)),
  146. ?assertEqual(P, gproc:where(From)),
  147. ?assertEqual(ok, t_call(P, die)).
  148. t_give_away_to_self() ->
  149. From = {n, l, foo},
  150. Me = self(),
  151. ?assertEqual(true, gproc:reg(From, undefined)),
  152. ?assertEqual(Me, gproc:where(From)),
  153. ?assertEqual(Me, gproc:give_away(From, Me)),
  154. ?assertEqual(Me, gproc:where(From)),
  155. ?assertEqual(true, gproc:unreg(From)).
  156. t_give_away_badarg() ->
  157. From = {n, l, foo},
  158. Me = self(),
  159. ?assertEqual(undefined, gproc:where(From)),
  160. ?assertError(badarg, gproc:give_away(From, Me)).
  161. t_give_away_to_unknown() ->
  162. From = {n, l, foo},
  163. Unknown = {n, l, unknown},
  164. Me = self(),
  165. ?assertEqual(true, gproc:reg(From, undefined)),
  166. ?assertEqual(Me, gproc:where(From)),
  167. ?assertEqual(undefined, gproc:where(Unknown)),
  168. ?assertEqual(undefined, gproc:give_away(From, Unknown)),
  169. ?assertEqual(undefined, gproc:where(From)).
  170. t_give_away_and_back() ->
  171. From = {n, l, foo},
  172. Me = self(),
  173. P = spawn_link(fun t_loop/0),
  174. ?assertEqual(true, gproc:reg(From, undefined)),
  175. ?assertEqual(Me, gproc:where(From)),
  176. ?assertEqual(P, gproc:give_away(From, P)),
  177. ?assertEqual(P, gproc:where(From)),
  178. ?assertEqual(ok, t_call(P, {give_away, From})),
  179. ?assertEqual(Me, gproc:where(From)),
  180. ?assertEqual(ok, t_call(P, die)).
  181. t_select() ->
  182. ?assertEqual(true, gproc:reg({n, l, {n,1}}, x)),
  183. ?assertEqual(true, gproc:reg({n, l, {n,2}}, y)),
  184. ?assertEqual(true, gproc:reg({p, l, {p,1}}, x)),
  185. ?assertEqual(true, gproc:reg({p, l, {p,2}}, y)),
  186. ?assertEqual(true, gproc:reg({c, l, {c,1}}, 1)),
  187. ?assertEqual(true, gproc:reg({a, l, {c,1}}, undefined)),
  188. %% local names
  189. ?assertEqual(
  190. [{{n,l,{n,1}},self(),x},
  191. {{n,l,{n,2}},self(),y}], gproc:select(
  192. {local,names},
  193. [{{{n,l,'_'},'_','_'},[],['$_']}])),
  194. %% mactch local names on value
  195. ?assertEqual(
  196. [{{n,l,{n,1}},self(),x}], gproc:select(
  197. {local,names},
  198. [{{{n,l,'_'},'_',x},[],['$_']}])),
  199. %% match all on value
  200. ?assertEqual(
  201. [{{n,l,{n,1}},self(),x},
  202. {{p,l,{p,1}},self(),x}], gproc:select(
  203. {all,all},
  204. [{{{'_',l,'_'},'_',x},[],['$_']}])),
  205. %% match all on pid
  206. ?assertEqual(
  207. [{{a,l,{c,1}},self(),1},
  208. {{c,l,{c,1}},self(),1},
  209. {{n,l,{n,1}},self(),x},
  210. {{n,l,{n,2}},self(),y},
  211. {{p,l,{p,1}},self(),x},
  212. {{p,l,{p,2}},self(),y}
  213. ], gproc:select(
  214. {all,all},
  215. [{{'_',self(),'_'},[],['$_']}])).
  216. t_qlc() ->
  217. ?assertEqual(true, gproc:reg({n, l, {n,1}}, x)),
  218. ?assertEqual(true, gproc:reg({n, l, {n,2}}, y)),
  219. ?assertEqual(true, gproc:reg({p, l, {p,1}}, x)),
  220. ?assertEqual(true, gproc:reg({p, l, {p,2}}, y)),
  221. ?assertEqual(true, gproc:reg({c, l, {c,1}}, 1)),
  222. ?assertEqual(true, gproc:reg({a, l, {c,1}}, undefined)),
  223. %% local names
  224. Exp1 = [{{n,l,{n,1}},self(),x},
  225. {{n,l,{n,2}},self(),y}],
  226. ?assertEqual(Exp1,
  227. qlc:e(qlc:q([N || N <- gproc:table(names)]))),
  228. ?assertEqual(Exp1,
  229. qlc:e(qlc:q([N || {{n,l,_},_,_} = N <- gproc:table(names)]))),
  230. %% mactch local names on value
  231. Exp2 = [{{n,l,{n,1}},self(),x}],
  232. ?assertEqual(Exp2,
  233. qlc:e(qlc:q([N || {{n,l,_},_,x} = N <- gproc:table(names)]))),
  234. %% match all on value
  235. Exp3 = [{{n,l,{n,1}},self(),x},
  236. {{p,l,{p,1}},self(),x}],
  237. ?assertEqual(Exp3,
  238. qlc:e(qlc:q([N || {_,_,x} = N <- gproc:table(all)]))),
  239. %% match all
  240. Exp4 = [{{a,l,{c,1}},self(),1},
  241. {{c,l,{c,1}},self(),1},
  242. {{n,l,{n,1}},self(),x},
  243. {{n,l,{n,2}},self(),y},
  244. {{p,l,{p,1}},self(),x},
  245. {{p,l,{p,2}},self(),y}
  246. ],
  247. ?assertEqual(Exp4,
  248. qlc:e(qlc:q([X || X <- gproc:table(all)]))),
  249. %% match on pid
  250. ?assertEqual(Exp4,
  251. qlc:e(qlc:q([{K,P,V} || {K,P,V} <-
  252. gproc:table(all), P =:= self()]))),
  253. ?assertEqual(Exp4,
  254. qlc:e(qlc:q([{K,P,V} || {K,P,V} <-
  255. gproc:table(all), P == self()]))).
  256. t_get_env() ->
  257. ?assertEqual(ok, application:set_env(gproc, ssss, "s1")),
  258. ?assertEqual(true, os:putenv("SSSS", "s2")),
  259. ?assertEqual(true, os:putenv("TTTT", "s3")),
  260. ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
  261. ?assertEqual(undefined, gproc:get_env(l, gproc, ssss, [])),
  262. ?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env])),
  263. ?assertEqual("s2", gproc:get_env(l, gproc, ssss, [os_env])),
  264. ?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env, os_env])),
  265. ?assertEqual("s3", gproc:get_env(l, gproc, ssss, [{os_env,"TTTT"}])),
  266. ?assertEqual("s4", gproc:get_env(l, gproc, ssss, [{default,"s4"}])).
  267. t_get_set_env() ->
  268. ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
  269. ?assertEqual(a, gproc:get_set_env(l, gproc, aaaa, [app_env])),
  270. ?assertEqual(ok, application:set_env(gproc, aaaa, undefined)),
  271. ?assertEqual(a, gproc:get_env(l, gproc, aaaa, [error])).
  272. t_set_env() ->
  273. ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
  274. ?assertEqual(a, gproc:get_set_env(l, gproc, aaaa, [app_env])),
  275. ?assertEqual(ok, application:set_env(gproc, aaaa, undefined)),
  276. ?assertEqual(b, gproc:set_env(l, gproc, aaaa, b, [app_env])),
  277. ?assertEqual({ok,b}, application:get_env(gproc, aaaa)),
  278. %%
  279. ?assertEqual(true, os:putenv("SSSS", "s0")),
  280. ?assertEqual("s0", gproc:get_env(l, gproc, ssss, [os_env])),
  281. ?assertEqual("s1", gproc:set_env(l, gproc, ssss, "s1", [os_env])),
  282. ?assertEqual("s1", os:getenv("SSSS")),
  283. ?assertEqual(true, os:putenv("SSSS", "s0")),
  284. ?assertEqual([{self(),"s1"}],
  285. gproc:lookup_values({p,l,{gproc_env,gproc,ssss}})).
  286. t_loop() ->
  287. receive
  288. {From, {give_away, Key}} ->
  289. ?assertEqual(From, gproc:give_away(Key, From)),
  290. From ! {self(), ok},
  291. t_loop();
  292. {From, die} ->
  293. From ! {self(), ok}
  294. end.
  295. t_call(P, Msg) ->
  296. P ! {self(), Msg},
  297. receive
  298. {P, Reply} ->
  299. Reply
  300. end.
  301. spawn_helper() ->
  302. Parent = self(),
  303. P = spawn(fun() ->
  304. ?assert(gproc:reg({n,l,self()}) =:= true),
  305. Ref = erlang:monitor(process, Parent),
  306. Parent ! {ok,self()},
  307. receive
  308. {'DOWN', Ref, _, _, _} ->
  309. ok
  310. end
  311. end),
  312. receive
  313. {ok,P} ->
  314. P
  315. end.
  316. give_gproc_some_time(T) ->
  317. timer:sleep(T),
  318. sys:get_status(gproc).
  319. -endif.