syn_registry_SUITE.erl 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561
  1. %% ==========================================================================================================
  2. %% Syn - A global Process Registry and Process Group manager.
  3. %%
  4. %% The MIT License (MIT)
  5. %%
  6. %% Copyright (c) 2015-2021 Roberto Ostinelli <roberto@ostinelli.net> and Neato Robotics, Inc.
  7. %%
  8. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  9. %% of this software and associated documentation files (the "Software"), to deal
  10. %% in the Software without restriction, including without limitation the rights
  11. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. %% copies of the Software, and to permit persons to whom the Software is
  13. %% furnished to do so, subject to the following conditions:
  14. %%
  15. %% The above copyright notice and this permission notice shall be included in
  16. %% all copies or substantial portions of the Software.
  17. %%
  18. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. %% THE SOFTWARE.
  25. %% ==========================================================================================================
  26. -module(syn_registry_SUITE).
  27. %% callbacks
  28. -export([all/0]).
  29. -export([init_per_suite/1, end_per_suite/1]).
  30. -export([groups/0, init_per_group/2, end_per_group/2]).
  31. -export([init_per_testcase/2, end_per_testcase/2]).
  32. %% tests
  33. -export([
  34. one_node_via_register_unregister/1,
  35. one_node_strict_mode/1
  36. ]).
  37. -export([
  38. three_nodes_discover/1,
  39. three_nodes_register_unregister_and_monitor/1,
  40. three_nodes_register_filter_unknown_node/1,
  41. three_nodes_cluster_changes/1,
  42. three_nodes_cluster_conflicts/1,
  43. three_nodes_custom_event_handler_reg_unreg/1,
  44. three_nodes_custom_event_handler_conflict_resolution/1
  45. ]).
  46. -export([
  47. four_nodes_concurrency/1
  48. ]).
  49. %% include
  50. -include_lib("common_test/include/ct.hrl").
  51. -include_lib("syn/src/syn.hrl").
  52. %% ===================================================================
  53. %% Callbacks
  54. %% ===================================================================
  55. %% -------------------------------------------------------------------
  56. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  57. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  58. %% GroupName = atom()
  59. %% TestCase = atom()
  60. %% Reason = any()
  61. %% -------------------------------------------------------------------
  62. all() ->
  63. [
  64. {group, one_node_registry},
  65. {group, three_nodes_registry},
  66. {group, four_nodes_registry}
  67. ].
  68. %% -------------------------------------------------------------------
  69. %% Function: groups() -> [Group]
  70. %% Group = {GroupName,Properties,GroupsAndTestCases}
  71. %% GroupName = atom()
  72. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  73. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  74. %% TestCase = atom()
  75. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  76. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  77. %% repeat_until_any_ok | repeat_until_any_fail
  78. %% N = integer() | forever
  79. %% -------------------------------------------------------------------
  80. groups() ->
  81. [
  82. {one_node_registry, [shuffle], [
  83. one_node_via_register_unregister,
  84. one_node_strict_mode
  85. ]},
  86. {three_nodes_registry, [shuffle], [
  87. three_nodes_discover,
  88. three_nodes_register_unregister_and_monitor,
  89. three_nodes_register_filter_unknown_node,
  90. three_nodes_cluster_changes,
  91. three_nodes_cluster_conflicts,
  92. three_nodes_custom_event_handler_reg_unreg,
  93. three_nodes_custom_event_handler_conflict_resolution
  94. ]},
  95. {four_nodes_registry, [shuffle], [
  96. four_nodes_concurrency
  97. ]}
  98. ].
  99. %% -------------------------------------------------------------------
  100. %% Function: init_per_suite(Config0) ->
  101. %% Config1 | {skip,Reason} |
  102. %% {skip_and_save,Reason,Config1}
  103. %% Config0 = Config1 = [tuple()]
  104. %% Reason = any()
  105. %% -------------------------------------------------------------------
  106. init_per_suite(Config) ->
  107. Config.
  108. %% -------------------------------------------------------------------
  109. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  110. %% Config0 = Config1 = [tuple()]
  111. %% -------------------------------------------------------------------
  112. end_per_suite(_Config) ->
  113. ok.
  114. %% -------------------------------------------------------------------
  115. %% Function: init_per_group(GroupName, Config0) ->
  116. %% Config1 | {skip,Reason} |
  117. %% {skip_and_save,Reason,Config1}
  118. %% GroupName = atom()
  119. %% Config0 = Config1 = [tuple()]
  120. %% Reason = any()
  121. %% -------------------------------------------------------------------
  122. init_per_group(three_nodes_registry, Config) ->
  123. case syn_test_suite_helper:init_cluster(3) of
  124. {error_initializing_cluster, Other} ->
  125. end_per_group(three_nodes_registry, Config),
  126. {skip, Other};
  127. NodesConfig ->
  128. NodesConfig ++ Config
  129. end;
  130. init_per_group(four_nodes_registry, Config) ->
  131. case syn_test_suite_helper:init_cluster(4) of
  132. {error_initializing_cluster, Other} ->
  133. end_per_group(four_nodes_registry, Config),
  134. {skip, Other};
  135. NodesConfig ->
  136. NodesConfig ++ Config
  137. end;
  138. init_per_group(_GroupName, Config) ->
  139. Config.
  140. %% -------------------------------------------------------------------
  141. %% Function: end_per_group(GroupName, Config0) ->
  142. %% void() | {save_config,Config1}
  143. %% GroupName = atom()
  144. %% Config0 = Config1 = [tuple()]
  145. %% -------------------------------------------------------------------
  146. end_per_group(three_nodes_registry, Config) ->
  147. syn_test_suite_helper:end_cluster(3, Config);
  148. end_per_group(four_nodes_registry, Config) ->
  149. syn_test_suite_helper:end_cluster(4, Config);
  150. end_per_group(_GroupName, _Config) ->
  151. syn_test_suite_helper:clean_after_test().
  152. %% -------------------------------------------------------------------
  153. %% Function: init_per_testcase(TestCase, Config0) ->
  154. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  155. %% TestCase = atom()
  156. %% Config0 = Config1 = [tuple()]
  157. %% Reason = any()
  158. %% -------------------------------------------------------------------
  159. init_per_testcase(TestCase, Config) ->
  160. ct:pal("Starting test: ~p", [TestCase]),
  161. Config.
  162. %% -------------------------------------------------------------------
  163. %% Function: end_per_testcase(TestCase, Config0) ->
  164. %% void() | {save_config,Config1} | {fail,Reason}
  165. %% TestCase = atom()
  166. %% Config0 = Config1 = [tuple()]
  167. %% Reason = any()
  168. %% -------------------------------------------------------------------
  169. end_per_testcase(_, _Config) ->
  170. syn_test_suite_helper:clean_after_test().
  171. %% ===================================================================
  172. %% Tests
  173. %% ===================================================================
  174. one_node_via_register_unregister(_Config) ->
  175. %% start syn
  176. ok = syn:start(),
  177. %% ---> scope
  178. syn:add_node_to_scopes([scope]),
  179. %% start gen server via syn
  180. GenServerNameCustom = {scope, <<"my proc">>},
  181. TupleCustom = {via, syn, GenServerNameCustom},
  182. {ok, PidCustom} = syn_test_gen_server:start_link(TupleCustom),
  183. %% retrieve
  184. {PidCustom, undefined} = syn:lookup(scope, <<"my proc">>),
  185. %% call
  186. pong = syn_test_gen_server:ping(TupleCustom),
  187. %% send via syn
  188. syn:send(GenServerNameCustom, {self(), send_ping}),
  189. syn_test_suite_helper:assert_received_messages([
  190. reply_pong
  191. ]),
  192. %% stop server
  193. syn_test_gen_server:stop(TupleCustom),
  194. %% retrieve
  195. syn_test_suite_helper:assert_wait(
  196. undefined,
  197. fun() -> syn:lookup(scope, <<"my proc">>) end
  198. ),
  199. %% send via syn
  200. {badarg, {GenServerNameCustom, anything}} = (catch syn:send(GenServerNameCustom, anything)).
  201. one_node_strict_mode(_Config) ->
  202. %% start syn
  203. ok = syn:start(),
  204. syn:add_node_to_scopes([scope]),
  205. %% start process
  206. Pid = syn_test_suite_helper:start_process(),
  207. %% strict mode disabled
  208. ok = syn:register(scope, "strict-false", Pid, metadata),
  209. ok = syn:register(scope, "strict-false", Pid, metadata),
  210. {error, non_strict_update} = syn:register(scope, "strict-false", Pid, new_metadata),
  211. {Pid, metadata} = syn:lookup(scope, "strict-false"),
  212. ok = syn:register(scope, "strict-false", Pid, metadata),
  213. %% strict mode enabled
  214. application:set_env(syn, strict_mode, true),
  215. {error, not_self} = syn:register(scope, "strict-true", Pid, metadata),
  216. Self = self(),
  217. ok = syn:register(scope, "strict-true", Self, metadata),
  218. ok = syn:register(scope, "strict-true", Self, new_metadata),
  219. {Self, new_metadata} = syn:lookup(scope, "strict-true"),
  220. ok = syn:register(scope, "strict-true", Self),
  221. {Self, undefined} = syn:lookup(scope, "strict-true").
  222. three_nodes_discover(Config) ->
  223. %% get slaves
  224. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  225. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  226. %% add scopes partially with ENV
  227. ok = rpc:call(SlaveNode2, application, set_env, [syn, scopes, [scope_all]]),
  228. %% start syn on nodes
  229. ok = syn:start(),
  230. ok = rpc:call(SlaveNode1, syn, start, []),
  231. ok = rpc:call(SlaveNode2, syn, start, []),
  232. %% add scopes
  233. ok = syn:add_node_to_scopes([scope_ab]),
  234. ok = syn:add_node_to_scopes([scope_all]),
  235. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_ab, scope_bc, scope_all]]),
  236. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_bc, scope_c]]),
  237. %% subcluster_nodes should return invalid errors
  238. {'EXIT', {{invalid_scope, custom_abcdef}, _}} = (catch syn_registry:subcluster_nodes(custom_abcdef)),
  239. %% check
  240. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_ab, [SlaveNode1]),
  241. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_all, [SlaveNode1, SlaveNode2]),
  242. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_ab, [node()]),
  243. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_bc, [SlaveNode2]),
  244. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_all, [node(), SlaveNode2]),
  245. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_bc, [SlaveNode1]),
  246. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_c, []),
  247. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_all, [node(), SlaveNode1]),
  248. %% disconnect node 2 (node 1 can still see node 2)
  249. syn_test_suite_helper:disconnect_node(SlaveNode2),
  250. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1]),
  251. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  252. %% check
  253. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_ab, [SlaveNode1]),
  254. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_all, [SlaveNode1]),
  255. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_ab, [node()]),
  256. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_bc, [SlaveNode2]),
  257. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_all, [node(), SlaveNode2]),
  258. %% reconnect node 2
  259. syn_test_suite_helper:connect_node(SlaveNode2),
  260. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  261. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  262. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  263. %% check
  264. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_ab, [SlaveNode1]),
  265. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_all, [SlaveNode1, SlaveNode2]),
  266. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_ab, [node()]),
  267. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_bc, [SlaveNode2]),
  268. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_all, [node(), SlaveNode2]),
  269. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_bc, [SlaveNode1]),
  270. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_c, []),
  271. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_all, [node(), SlaveNode1]),
  272. %% crash a scope process on 2
  273. rpc:call(SlaveNode2, syn_test_suite_helper, kill_process, [syn_registry_scope_bc]),
  274. rpc:call(SlaveNode2, syn_test_suite_helper, wait_process_name_ready, [syn_registry_scope_bc]),
  275. %% check
  276. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_ab, [SlaveNode1]),
  277. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_all, [SlaveNode1, SlaveNode2]),
  278. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_ab, [node()]),
  279. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_bc, [SlaveNode2]),
  280. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_all, [node(), SlaveNode2]),
  281. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_bc, [SlaveNode1]),
  282. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_c, []),
  283. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_all, [node(), SlaveNode1]),
  284. %% crash scopes supervisor on local
  285. syn_test_suite_helper:kill_process(syn_scopes_sup),
  286. syn_test_suite_helper:wait_process_name_ready(syn_registry_scope_ab),
  287. syn_test_suite_helper:wait_process_name_ready(syn_registry_scope_all),
  288. %% check
  289. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_ab, [SlaveNode1]),
  290. syn_test_suite_helper:assert_registry_scope_subcluster(node(), scope_all, [SlaveNode1, SlaveNode2]),
  291. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_ab, [node()]),
  292. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_bc, [SlaveNode2]),
  293. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode1, scope_all, [node(), SlaveNode2]),
  294. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_bc, [SlaveNode1]),
  295. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_c, []),
  296. syn_test_suite_helper:assert_registry_scope_subcluster(SlaveNode2, scope_all, [node(), SlaveNode1]).
  297. three_nodes_register_unregister_and_monitor(Config) ->
  298. %% get slaves
  299. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  300. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  301. %% start syn on nodes
  302. ok = syn:start(),
  303. ok = rpc:call(SlaveNode1, syn, start, []),
  304. ok = rpc:call(SlaveNode2, syn, start, []),
  305. %% add scopes
  306. ok = syn:add_node_to_scopes([scope_ab]),
  307. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_ab, scope_bc]]),
  308. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_bc]]),
  309. %% start processes
  310. Pid = syn_test_suite_helper:start_process(),
  311. PidWithMeta = syn_test_suite_helper:start_process(),
  312. PidRemoteWithMetaOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  313. %% retrieve
  314. undefined = syn:lookup(scope_ab, "scope_a"),
  315. undefined = rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a"]),
  316. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a"])),
  317. undefined = syn:lookup(scope_ab, "scope_a_alias"),
  318. undefined = rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a_alias"]),
  319. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a_alias"])),
  320. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, {remote_scoped_bc})),
  321. undefined = rpc:call(SlaveNode1, syn, lookup, [scope_bc, {remote_scoped_bc}]),
  322. undefined = rpc:call(SlaveNode2, syn, lookup, [scope_bc, {remote_scoped_bc}]),
  323. 0 = syn:registry_count(scope_ab),
  324. 0 = syn:registry_count(scope_ab, node()),
  325. 0 = syn:registry_count(scope_ab, SlaveNode1),
  326. 0 = syn:registry_count(scope_ab, SlaveNode2),
  327. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc)),
  328. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, node())),
  329. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode1)),
  330. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode2)),
  331. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab]),
  332. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, node()]),
  333. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, SlaveNode1]),
  334. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, SlaveNode2]),
  335. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  336. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  337. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  338. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  339. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab])),
  340. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, node()])),
  341. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, SlaveNode1])),
  342. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, SlaveNode2])),
  343. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  344. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  345. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  346. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  347. %% register
  348. ok = syn:register(scope_ab, "scope_a", Pid),
  349. ok = syn:register(scope_ab, "scope_a_alias", PidWithMeta, <<"with_meta">>),
  350. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:register(scope_bc, "scope_a", Pid)),
  351. {'EXIT', {{invalid_scope, non_existent_scope}, _}} = (catch syn:register(non_existent_scope, "scope_a", Pid)),
  352. ok = rpc:call(SlaveNode2, syn, register, [scope_bc, {remote_scoped_bc}, PidRemoteWithMetaOn1, <<"with_meta 1">>]),
  353. %% errors
  354. {error, taken} = syn:register(scope_ab, "scope_a", PidWithMeta),
  355. {error, not_alive} = syn:register(scope_ab, {"pid not alive"}, list_to_pid("<0.9999.0>")),
  356. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:register(scope_bc, "scope_a_noscope", Pid)),
  357. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:unregister(scope_bc, "scope_a_noscope")),
  358. LocalNode = node(),
  359. {badrpc, {'EXIT', {{invalid_remote_scope, scope_bc, LocalNode}, _}}} = (catch rpc:call(SlaveNode1, syn, register, [scope_bc, "pid-outside", Pid])),
  360. %% retrieve
  361. syn_test_suite_helper:assert_wait(
  362. {Pid, undefined},
  363. fun() -> syn:lookup(scope_ab, "scope_a") end
  364. ),
  365. syn_test_suite_helper:assert_wait(
  366. {Pid, undefined},
  367. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a"]) end
  368. ),
  369. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a"])),
  370. syn_test_suite_helper:assert_wait(
  371. {PidWithMeta, <<"with_meta">>},
  372. fun() -> syn:lookup(scope_ab, "scope_a_alias") end
  373. ),
  374. syn_test_suite_helper:assert_wait(
  375. {PidWithMeta, <<"with_meta">>},
  376. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a_alias"]) end
  377. ),
  378. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a_alias"])),
  379. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, {remote_scoped_bc})),
  380. syn_test_suite_helper:assert_wait(
  381. {PidRemoteWithMetaOn1, <<"with_meta 1">>},
  382. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, {remote_scoped_bc}]) end
  383. ),
  384. syn_test_suite_helper:assert_wait(
  385. {PidRemoteWithMetaOn1, <<"with_meta 1">>},
  386. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, {remote_scoped_bc}]) end
  387. ),
  388. 2 = syn:registry_count(scope_ab),
  389. 2 = syn:registry_count(scope_ab, node()),
  390. 0 = syn:registry_count(scope_ab, SlaveNode1),
  391. 0 = syn:registry_count(scope_ab, SlaveNode2),
  392. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc)),
  393. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, node())),
  394. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode1)),
  395. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode2)),
  396. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab]),
  397. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, node()]),
  398. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, SlaveNode1]),
  399. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, SlaveNode2]),
  400. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  401. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  402. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  403. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  404. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab])),
  405. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, node()])),
  406. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, SlaveNode1])),
  407. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, SlaveNode2])),
  408. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  409. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  410. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  411. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  412. %% enable strict to allow for updates
  413. application:set_env(syn, strict_mode, true),
  414. %% re-register to edit meta (strict is enabled, so send message)
  415. PidWithMeta ! {registry_update_meta, scope_ab, "scope_a_alias", <<"with_meta_updated">>},
  416. syn_test_suite_helper:assert_wait(
  417. {PidWithMeta, <<"with_meta_updated">>},
  418. fun() -> syn:lookup(scope_ab, "scope_a_alias") end
  419. ),
  420. syn_test_suite_helper:assert_wait(
  421. {PidWithMeta, <<"with_meta_updated">>},
  422. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a_alias"]) end
  423. ),
  424. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a_alias"])),
  425. %% disable strict
  426. application:set_env(syn, strict_mode, false),
  427. %% register remote
  428. ok = syn:register(scope_ab, "ab_on_1", PidRemoteWithMetaOn1, <<"ab-on-1">>),
  429. syn_test_suite_helper:assert_wait(
  430. {PidRemoteWithMetaOn1, <<"ab-on-1">>},
  431. fun() -> syn:lookup(scope_ab, "ab_on_1") end
  432. ),
  433. %% crash scope process to ensure that monitors get recreated & data received from other nodes
  434. syn_test_suite_helper:kill_process(syn_registry_scope_ab),
  435. syn_test_suite_helper:wait_process_name_ready(syn_registry_scope_ab),
  436. %% check remote has been sync'ed back
  437. syn_test_suite_helper:assert_wait(
  438. {PidRemoteWithMetaOn1, <<"ab-on-1">>},
  439. fun() -> syn:lookup(scope_ab, "ab_on_1") end
  440. ),
  441. %% kill process
  442. syn_test_suite_helper:kill_process(Pid),
  443. syn_test_suite_helper:kill_process(PidWithMeta),
  444. %% unregister processes
  445. {error, undefined} = (catch syn:unregister(scope_ab, <<"my proc with meta">>)),
  446. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:unregister(scope_bc, <<"my proc with meta">>)),
  447. ok = rpc:call(SlaveNode1, syn, unregister, [scope_bc, {remote_scoped_bc}]),
  448. %% retrieve
  449. syn_test_suite_helper:assert_wait(
  450. undefined,
  451. fun() -> syn:lookup(scope_ab, "scope_a") end
  452. ),
  453. syn_test_suite_helper:assert_wait(
  454. undefined,
  455. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a"]) end
  456. ),
  457. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a"])),
  458. syn_test_suite_helper:assert_wait(
  459. undefined,
  460. fun() -> syn:lookup(scope_ab, "scope_a_alias") end
  461. ),
  462. syn_test_suite_helper:assert_wait(
  463. undefined,
  464. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_ab, "scope_a_alias"]) end
  465. ),
  466. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, lookup, [scope_ab, "scope_a_alias"])),
  467. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, {remote_scoped_bc})),
  468. syn_test_suite_helper:assert_wait(
  469. undefined,
  470. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, {remote_scoped_bc}]) end
  471. ),
  472. syn_test_suite_helper:assert_wait(
  473. undefined,
  474. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, {remote_scoped_bc}]) end
  475. ),
  476. 1 = syn:registry_count(scope_ab),
  477. 0 = syn:registry_count(scope_ab, node()),
  478. 1 = syn:registry_count(scope_ab, SlaveNode1),
  479. 0 = syn:registry_count(scope_ab, SlaveNode2),
  480. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc)),
  481. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, node())),
  482. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode1)),
  483. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode2)),
  484. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab]),
  485. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, node()]),
  486. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, SlaveNode1]),
  487. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_ab, SlaveNode2]),
  488. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  489. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  490. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  491. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  492. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab])),
  493. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, node()])),
  494. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, SlaveNode1])),
  495. {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, registry_count, [scope_ab, SlaveNode2])),
  496. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  497. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  498. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  499. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  500. %% errors
  501. {error, undefined} = syn:unregister(scope_ab, {invalid_name}),
  502. %% (simulate race condition)
  503. Pid1 = syn_test_suite_helper:start_process(),
  504. Pid2 = syn_test_suite_helper:start_process(),
  505. ok = syn:register(scope_ab, <<"my proc">>, Pid1),
  506. syn_test_suite_helper:assert_wait(
  507. {Pid1, undefined},
  508. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_ab, <<"my proc">>]) end
  509. ),
  510. remove_from_local_table(scope_ab, <<"my proc">>, Pid1),
  511. add_to_local_table(scope_ab, <<"my proc">>, Pid2, undefined, 0, undefined),
  512. {error, race_condition} = rpc:call(SlaveNode1, syn, unregister, [scope_ab, <<"my proc">>]).
  513. three_nodes_register_filter_unknown_node(Config) ->
  514. %% get slaves
  515. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  516. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  517. %% start syn on 1 and 2
  518. ok = rpc:call(SlaveNode1, syn, start, []),
  519. ok = rpc:call(SlaveNode2, syn, start, []),
  520. %% add scopes
  521. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_bc]]),
  522. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_bc]]),
  523. %% send sync message from out of scope node
  524. InvalidPid = syn_test_suite_helper:start_process(),
  525. {syn_registry_scope_bc, SlaveNode1} ! {'3.0', sync_register, <<"proc-name">>, InvalidPid, undefined, os:system_time(millisecond), normal},
  526. %% check
  527. undefined = rpc:call(SlaveNode1, syn, lookup, [scope_bc, <<"proc-name">>]).
  528. three_nodes_cluster_changes(Config) ->
  529. %% get slaves
  530. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  531. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  532. %% disconnect 1 from 2
  533. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  534. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  535. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  536. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  537. %% start syn on 1 and 2, nodes don't know of each other
  538. ok = rpc:call(SlaveNode1, syn, start, []),
  539. ok = rpc:call(SlaveNode2, syn, start, []),
  540. %% add scopes
  541. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_all, scope_bc]]),
  542. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_all, scope_bc]]),
  543. %% start processes
  544. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  545. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  546. %% register
  547. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-1", PidRemoteOn1, "meta-1"]),
  548. ok = rpc:call(SlaveNode2, syn, register, [scope_all, "proc-2", PidRemoteOn2, "meta-2"]),
  549. ok = rpc:call(SlaveNode1, syn, register, [scope_bc, "BC-proc-1", PidRemoteOn1, "meta-1"]),
  550. ok = rpc:call(SlaveNode1, syn, register, [scope_bc, "BC-proc-1 alias", PidRemoteOn1, "meta-1 alias"]),
  551. %% form full cluster
  552. ok = syn:start(),
  553. ok = syn:add_node_to_scopes([scope_all]),
  554. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  555. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  556. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  557. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  558. %% retrieve
  559. syn_test_suite_helper:assert_wait(
  560. {PidRemoteOn1, "meta-1"},
  561. fun() -> syn:lookup(scope_all, "proc-1") end
  562. ),
  563. syn_test_suite_helper:assert_wait(
  564. {PidRemoteOn1, "meta-1"},
  565. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-1"]) end
  566. ),
  567. syn_test_suite_helper:assert_wait(
  568. {PidRemoteOn1, "meta-1"},
  569. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-1"]) end
  570. ),
  571. syn_test_suite_helper:assert_wait(
  572. {PidRemoteOn2, "meta-2"},
  573. fun() -> syn:lookup(scope_all, "proc-2") end
  574. ),
  575. syn_test_suite_helper:assert_wait(
  576. {PidRemoteOn2, "meta-2"},
  577. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-2"]) end
  578. ),
  579. syn_test_suite_helper:assert_wait(
  580. {PidRemoteOn2, "meta-2"},
  581. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-2"]) end
  582. ),
  583. 2 = syn:registry_count(scope_all),
  584. 0 = syn:registry_count(scope_all, node()),
  585. 1 = syn:registry_count(scope_all, SlaveNode1),
  586. 1 = syn:registry_count(scope_all, SlaveNode2),
  587. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  588. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  589. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  590. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  591. 2 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  592. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  593. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  594. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  595. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, "BC-proc-1")),
  596. syn_test_suite_helper:assert_wait(
  597. {PidRemoteOn1, "meta-1"},
  598. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "BC-proc-1"]) end
  599. ),
  600. syn_test_suite_helper:assert_wait(
  601. {PidRemoteOn1, "meta-1"},
  602. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "BC-proc-1"]) end
  603. ),
  604. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, "BC-proc-1 alias")),
  605. syn_test_suite_helper:assert_wait(
  606. {PidRemoteOn1, "meta-1 alias"},
  607. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "BC-proc-1 alias"]) end
  608. ),
  609. syn_test_suite_helper:assert_wait(
  610. {PidRemoteOn1, "meta-1 alias"},
  611. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "BC-proc-1 alias"]) end
  612. ),
  613. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc)),
  614. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, node())),
  615. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode1)),
  616. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc, SlaveNode2)),
  617. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  618. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  619. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  620. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  621. 2 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  622. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  623. 2 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  624. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  625. %% partial netsplit (1 cannot see 2)
  626. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  627. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  628. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  629. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  630. %% retrieve
  631. syn_test_suite_helper:assert_wait(
  632. {PidRemoteOn1, "meta-1"},
  633. fun() -> syn:lookup(scope_all, "proc-1") end
  634. ),
  635. syn_test_suite_helper:assert_wait(
  636. {PidRemoteOn1, "meta-1"},
  637. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-1"]) end
  638. ),
  639. syn_test_suite_helper:assert_wait(
  640. undefined,
  641. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-1"]) end
  642. ),
  643. syn_test_suite_helper:assert_wait(
  644. {PidRemoteOn2, "meta-2"},
  645. fun() -> syn:lookup(scope_all, "proc-2") end
  646. ),
  647. syn_test_suite_helper:assert_wait(
  648. undefined,
  649. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-2"]) end
  650. ),
  651. syn_test_suite_helper:assert_wait(
  652. {PidRemoteOn2, "meta-2"},
  653. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-2"]) end
  654. ),
  655. 2 = syn:registry_count(scope_all),
  656. 0 = syn:registry_count(scope_all, node()),
  657. 1 = syn:registry_count(scope_all, SlaveNode1),
  658. 1 = syn:registry_count(scope_all, SlaveNode2),
  659. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  660. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  661. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  662. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  663. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  664. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  665. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  666. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  667. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, "BC-proc-1")),
  668. syn_test_suite_helper:assert_wait(
  669. {PidRemoteOn1, "meta-1"},
  670. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "BC-proc-1"]) end
  671. ),
  672. syn_test_suite_helper:assert_wait(
  673. undefined,
  674. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "BC-proc-1"]) end
  675. ),
  676. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, "BC-proc-1 alias")),
  677. syn_test_suite_helper:assert_wait(
  678. {PidRemoteOn1, "meta-1 alias"},
  679. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "BC-proc-1 alias"]) end
  680. ),
  681. syn_test_suite_helper:assert_wait(
  682. undefined,
  683. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "BC-proc-1 alias"]) end
  684. ),
  685. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc)),
  686. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  687. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  688. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  689. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  690. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  691. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  692. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  693. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  694. %% re-join
  695. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  696. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  697. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  698. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  699. %% retrieve
  700. syn_test_suite_helper:assert_wait(
  701. {PidRemoteOn1, "meta-1"},
  702. fun() -> syn:lookup(scope_all, "proc-1") end
  703. ),
  704. syn_test_suite_helper:assert_wait(
  705. {PidRemoteOn1, "meta-1"},
  706. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-1"]) end
  707. ),
  708. syn_test_suite_helper:assert_wait(
  709. {PidRemoteOn1, "meta-1"},
  710. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-1"]) end
  711. ),
  712. syn_test_suite_helper:assert_wait(
  713. {PidRemoteOn2, "meta-2"},
  714. fun() -> syn:lookup(scope_all, "proc-2") end
  715. ),
  716. syn_test_suite_helper:assert_wait(
  717. {PidRemoteOn2, "meta-2"},
  718. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-2"]) end
  719. ),
  720. syn_test_suite_helper:assert_wait(
  721. {PidRemoteOn2, "meta-2"},
  722. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-2"]) end
  723. ),
  724. 2 = syn:registry_count(scope_all),
  725. 0 = syn:registry_count(scope_all, node()),
  726. 1 = syn:registry_count(scope_all, SlaveNode1),
  727. 1 = syn:registry_count(scope_all, SlaveNode2),
  728. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  729. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  730. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  731. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  732. 2 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  733. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  734. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  735. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  736. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, "BC-proc-1")),
  737. syn_test_suite_helper:assert_wait(
  738. {PidRemoteOn1, "meta-1"},
  739. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "BC-proc-1"]) end
  740. ),
  741. syn_test_suite_helper:assert_wait(
  742. {PidRemoteOn1, "meta-1"},
  743. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "BC-proc-1"]) end
  744. ),
  745. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:lookup(scope_bc, "BC-proc-1 alias")),
  746. syn_test_suite_helper:assert_wait(
  747. {PidRemoteOn1, "meta-1 alias"},
  748. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "BC-proc-1 alias"]) end
  749. ),
  750. syn_test_suite_helper:assert_wait(
  751. {PidRemoteOn1, "meta-1 alias"},
  752. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "BC-proc-1 alias"]) end
  753. ),
  754. {'EXIT', {{invalid_scope, scope_bc}, _}} = (catch syn:registry_count(scope_bc)),
  755. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  756. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  757. 2 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  758. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  759. 2 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  760. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  761. 2 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  762. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]).
  763. three_nodes_cluster_conflicts(Config) ->
  764. %% get slaves
  765. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  766. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  767. %% start syn on nodes
  768. ok = syn:start(),
  769. ok = rpc:call(SlaveNode1, syn, start, []),
  770. ok = rpc:call(SlaveNode2, syn, start, []),
  771. %% add scopes
  772. ok = syn:add_node_to_scopes([scope_all]),
  773. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_all, scope_bc]]),
  774. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_all, scope_bc]]),
  775. %% partial netsplit (1 cannot see 2)
  776. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  777. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  778. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  779. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  780. %% start conflict processes
  781. Pid2RemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  782. Pid2RemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  783. %% --> conflict by netsplit
  784. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-confict-by-netsplit", Pid2RemoteOn1, "meta-1"]),
  785. ok = rpc:call(SlaveNode2, syn, register, [scope_all, "proc-confict-by-netsplit", Pid2RemoteOn2, "meta-2"]),
  786. ok = rpc:call(SlaveNode1, syn, register, [scope_bc, "proc-confict-by-netsplit-scoped", Pid2RemoteOn1, "meta-1"]),
  787. ok = rpc:call(SlaveNode2, syn, register, [scope_bc, "proc-confict-by-netsplit-scoped", Pid2RemoteOn2, "meta-2"]),
  788. %% re-join
  789. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  790. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  791. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  792. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  793. %% retrieve
  794. syn_test_suite_helper:assert_wait(
  795. {Pid2RemoteOn2, "meta-2"},
  796. fun() -> syn:lookup(scope_all, "proc-confict-by-netsplit") end
  797. ),
  798. syn_test_suite_helper:assert_wait(
  799. {Pid2RemoteOn2, "meta-2"},
  800. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-confict-by-netsplit"]) end
  801. ),
  802. syn_test_suite_helper:assert_wait(
  803. {Pid2RemoteOn2, "meta-2"},
  804. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-confict-by-netsplit"]) end
  805. ),
  806. 1 = syn:registry_count(scope_all),
  807. 0 = syn:registry_count(scope_all, node()),
  808. 0 = syn:registry_count(scope_all, SlaveNode1),
  809. 1 = syn:registry_count(scope_all, SlaveNode2),
  810. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  811. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  812. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  813. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  814. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  815. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  816. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  817. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  818. syn_test_suite_helper:assert_wait(
  819. {Pid2RemoteOn2, "meta-2"},
  820. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "proc-confict-by-netsplit-scoped"]) end
  821. ),
  822. syn_test_suite_helper:assert_wait(
  823. {Pid2RemoteOn2, "meta-2"},
  824. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "proc-confict-by-netsplit-scoped"]) end
  825. ),
  826. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  827. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  828. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  829. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  830. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  831. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  832. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  833. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  834. %% process alive
  835. syn_test_suite_helper:assert_wait(
  836. false,
  837. fun() -> rpc:call(SlaveNode1, erlang, is_process_alive, [Pid2RemoteOn1]) end
  838. ),
  839. syn_test_suite_helper:assert_wait(
  840. true,
  841. fun() -> rpc:call(SlaveNode2, erlang, is_process_alive, [Pid2RemoteOn2]) end
  842. ),
  843. %% --> conflict by race condition
  844. PidOnMaster = syn_test_suite_helper:start_process(),
  845. PidOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  846. rpc:call(SlaveNode1, syn_registry, add_to_local_table,
  847. [default, <<"my proc">>, PidOn1, "meta-2", erlang:system_time(), undefined]
  848. ),
  849. ok = syn:register(scope_all, <<"my proc">>, PidOnMaster, "meta-1"),
  850. %% retrieve
  851. syn_test_suite_helper:assert_wait(
  852. {PidOnMaster, "meta-1"},
  853. fun() -> syn:lookup(scope_all, <<"my proc">>) end
  854. ),
  855. syn_test_suite_helper:assert_wait(
  856. {PidOnMaster, "meta-1"},
  857. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, <<"my proc">>]) end
  858. ),
  859. syn_test_suite_helper:assert_wait(
  860. {PidOnMaster, "meta-1"},
  861. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, <<"my proc">>]) end
  862. ),
  863. %% NB: we can't check for process alive here because we injected the conflicting process in the DB
  864. %% -> it's not actually monitored
  865. ok.
  866. three_nodes_custom_event_handler_reg_unreg(Config) ->
  867. %% get slaves
  868. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  869. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  870. %% add custom handler for callbacks (using ENV)
  871. rpc:call(SlaveNode2, application, set_env, [syn, event_handler, syn_test_event_handler_callbacks]),
  872. %% start syn on nodes
  873. ok = syn:start(),
  874. ok = rpc:call(SlaveNode1, syn, start, []),
  875. ok = rpc:call(SlaveNode2, syn, start, []),
  876. %% add custom handler for callbacks (using method call)
  877. syn:set_event_handler(syn_test_event_handler_callbacks),
  878. rpc:call(SlaveNode1, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  879. %% add scopes
  880. ok = syn:add_node_to_scopes([scope_all]),
  881. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_all]]),
  882. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_all]]),
  883. %% init
  884. LocalNode = node(),
  885. %% start process
  886. Pid = syn_test_suite_helper:start_process(),
  887. Pid2 = syn_test_suite_helper:start_process(),
  888. %% ---> on registration
  889. ok = syn:register(scope_all, "proc-handler", Pid, {recipient, self(), <<"meta">>}),
  890. %% check callbacks called
  891. syn_test_suite_helper:assert_received_messages([
  892. {on_process_registered, LocalNode, scope_all, "proc-handler", Pid, <<"meta">>, normal},
  893. {on_process_registered, SlaveNode1, scope_all, "proc-handler", Pid, <<"meta">>, normal},
  894. {on_process_registered, SlaveNode2, scope_all, "proc-handler", Pid, <<"meta">>, normal}
  895. ]),
  896. %% registration from another node
  897. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-handler-2", Pid2, {recipient, self(), <<"meta-for-2">>}]),
  898. %% check callbacks called
  899. syn_test_suite_helper:assert_received_messages([
  900. {on_process_registered, LocalNode, scope_all, "proc-handler-2", Pid2, <<"meta-for-2">>, normal},
  901. {on_process_registered, SlaveNode1, scope_all, "proc-handler-2", Pid2, <<"meta-for-2">>, normal},
  902. {on_process_registered, SlaveNode2, scope_all, "proc-handler-2", Pid2, <<"meta-for-2">>, normal}
  903. ]),
  904. %% enable strict to allow for updates
  905. application:set_env(syn, strict_mode, true),
  906. %% ---> on meta update (strict is enabled, so send message)
  907. Pid ! {registry_update_meta, scope_all, "proc-handler", {recipient, self(), <<"new-meta">>}},
  908. %% check callbacks called
  909. syn_test_suite_helper:assert_received_messages([
  910. {on_registry_process_updated, LocalNode, scope_all, "proc-handler", Pid, <<"new-meta">>, normal},
  911. {on_registry_process_updated, SlaveNode1, scope_all, "proc-handler", Pid, <<"new-meta">>, normal},
  912. {on_registry_process_updated, SlaveNode2, scope_all, "proc-handler", Pid, <<"new-meta">>, normal}
  913. ]),
  914. %% ---> on unregister
  915. ok = syn:unregister(scope_all, "proc-handler"),
  916. %% check callbacks called
  917. syn_test_suite_helper:assert_received_messages([
  918. {on_process_unregistered, LocalNode, scope_all, "proc-handler", Pid, <<"new-meta">>, normal},
  919. {on_process_unregistered, SlaveNode1, scope_all, "proc-handler", Pid, <<"new-meta">>, normal},
  920. {on_process_unregistered, SlaveNode2, scope_all, "proc-handler", Pid, <<"new-meta">>, normal}
  921. ]),
  922. %% unregister from another node
  923. ok = rpc:call(SlaveNode1, syn, unregister, [scope_all, "proc-handler-2"]),
  924. %% check callbacks called
  925. syn_test_suite_helper:assert_received_messages([
  926. {on_process_unregistered, LocalNode, scope_all, "proc-handler-2", Pid2, <<"meta-for-2">>, normal},
  927. {on_process_unregistered, SlaveNode1, scope_all, "proc-handler-2", Pid2, <<"meta-for-2">>, normal},
  928. {on_process_unregistered, SlaveNode2, scope_all, "proc-handler-2", Pid2, <<"meta-for-2">>, normal}
  929. ]),
  930. %% clean & check
  931. syn_test_suite_helper:kill_process(Pid),
  932. %% no messages
  933. syn_test_suite_helper:assert_empty_queue(),
  934. %% disable strict
  935. application:set_env(syn, strict_mode, false),
  936. %% ---> after a netsplit
  937. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  938. ok = syn:register(scope_all, remote_on_1, PidRemoteOn1, {recipient, self(), <<"netsplit">>}),
  939. %% check callbacks called
  940. syn_test_suite_helper:assert_received_messages([
  941. {on_process_registered, LocalNode, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, normal},
  942. {on_process_registered, SlaveNode1, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, normal},
  943. {on_process_registered, SlaveNode2, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, normal}
  944. ]),
  945. %% partial netsplit (1 cannot see 2)
  946. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  947. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  948. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  949. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  950. %% check callbacks called
  951. syn_test_suite_helper:assert_received_messages([
  952. {on_process_unregistered, SlaveNode2, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, {syn_remote_scope_node_down, scope_all, SlaveNode1}}
  953. ]),
  954. %% ---> after a re-join
  955. %% re-join
  956. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  957. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  958. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  959. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  960. %% check callbacks called
  961. syn_test_suite_helper:assert_received_messages([
  962. {on_process_registered, SlaveNode2, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, {syn_remote_scope_node_up, scope_all, SlaveNode1}}
  963. ]),
  964. %% clean
  965. syn_test_suite_helper:kill_process(PidRemoteOn1),
  966. %% check callbacks called
  967. syn_test_suite_helper:assert_received_messages([
  968. {on_process_unregistered, LocalNode, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, killed},
  969. {on_process_unregistered, SlaveNode1, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, killed},
  970. {on_process_unregistered, SlaveNode2, scope_all, remote_on_1, PidRemoteOn1, <<"netsplit">>, killed}
  971. ]),
  972. %% ---> after a conflict resolution
  973. %% partial netsplit (1 cannot see 2)
  974. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  975. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  976. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  977. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  978. %% start conflict processes
  979. Pid2RemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  980. Pid2RemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  981. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-confict", Pid2RemoteOn1, {recipient, self(), <<"meta-1">>}]),
  982. ok = rpc:call(SlaveNode2, syn, register, [scope_all, "proc-confict", Pid2RemoteOn2, {recipient, self(), <<"meta-2">>}]),
  983. %% check callbacks called
  984. syn_test_suite_helper:assert_received_messages([
  985. {on_process_registered, LocalNode, scope_all, "proc-confict", Pid2RemoteOn1, <<"meta-1">>, normal},
  986. {on_process_unregistered, LocalNode, scope_all, "proc-confict", Pid2RemoteOn1, <<"meta-1">>, normal},
  987. {on_process_registered, LocalNode, scope_all, "proc-confict", Pid2RemoteOn2, <<"meta-2">>, normal},
  988. {on_process_registered, SlaveNode1, scope_all, "proc-confict", Pid2RemoteOn1, <<"meta-1">>, normal},
  989. {on_process_registered, SlaveNode2, scope_all, "proc-confict", Pid2RemoteOn2, <<"meta-2">>, normal}
  990. ]),
  991. %% re-join
  992. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  993. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  994. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  995. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  996. %% check callbacks called
  997. syn_test_suite_helper:assert_received_messages([
  998. {on_process_unregistered, SlaveNode1, scope_all, "proc-confict", Pid2RemoteOn1, <<"meta-1">>, syn_conflict_resolution},
  999. {on_process_registered, SlaveNode1, scope_all, "proc-confict", Pid2RemoteOn2, <<"meta-2">>, syn_conflict_resolution}
  1000. ]),
  1001. %% kill
  1002. syn_test_suite_helper:kill_process(Pid2RemoteOn1),
  1003. syn_test_suite_helper:kill_process(Pid2RemoteOn2),
  1004. %% check callbacks called
  1005. syn_test_suite_helper:assert_received_messages([
  1006. {on_process_unregistered, LocalNode, scope_all, "proc-confict", Pid2RemoteOn2, <<"meta-2">>, killed},
  1007. {on_process_unregistered, SlaveNode1, scope_all, "proc-confict", Pid2RemoteOn2, <<"meta-2">>, killed},
  1008. {on_process_unregistered, SlaveNode2, scope_all, "proc-confict", Pid2RemoteOn2, <<"meta-2">>, killed}
  1009. ]),
  1010. %% ---> don't call on monitor rebuild
  1011. %% crash the scope process on local
  1012. syn_test_suite_helper:kill_process(syn_registry_scope_all),
  1013. syn_test_suite_helper:wait_process_name_ready(syn_registry_scope_all),
  1014. %% no messages
  1015. syn_test_suite_helper:assert_empty_queue(),
  1016. %% ---> call if process died during the scope process crash
  1017. TransientPid = syn_test_suite_helper:start_process(),
  1018. ok = syn:register(scope_all, "transient-pid", TransientPid, {recipient, self(), "transient-meta"}),
  1019. %% check callbacks called
  1020. syn_test_suite_helper:assert_received_messages([
  1021. {on_process_registered, LocalNode, scope_all, "transient-pid", TransientPid, "transient-meta", normal},
  1022. {on_process_registered, SlaveNode1, scope_all, "transient-pid", TransientPid, "transient-meta", normal},
  1023. {on_process_registered, SlaveNode2, scope_all, "transient-pid", TransientPid, "transient-meta", normal}
  1024. ]),
  1025. %% crash the scope process & fake a died process on local
  1026. InvalidPid = list_to_pid("<0.9999.0>"),
  1027. add_to_local_table(scope_all, "invalid-pid", InvalidPid, {recipient, self(), "invalid-meta"}, 0, undefined),
  1028. syn_test_suite_helper:kill_process(syn_registry_scope_all),
  1029. %% check callbacks called
  1030. syn_test_suite_helper:assert_received_messages([
  1031. {on_process_unregistered, LocalNode, scope_all, "invalid-pid", InvalidPid, "invalid-meta", undefined},
  1032. {on_process_unregistered, SlaveNode1, scope_all, "transient-pid", TransientPid, "transient-meta", {syn_remote_scope_node_down, scope_all, LocalNode}},
  1033. {on_process_unregistered, SlaveNode2, scope_all, "transient-pid", TransientPid, "transient-meta", {syn_remote_scope_node_down, scope_all, LocalNode}},
  1034. {on_process_registered, SlaveNode1, scope_all, "transient-pid", TransientPid, "transient-meta", {syn_remote_scope_node_up, scope_all, LocalNode}},
  1035. {on_process_registered, SlaveNode2, scope_all, "transient-pid", TransientPid, "transient-meta", {syn_remote_scope_node_up, scope_all, LocalNode}}
  1036. ]).
  1037. three_nodes_custom_event_handler_conflict_resolution(Config) ->
  1038. %% get slaves
  1039. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  1040. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  1041. %% add custom handler for resolution & scopes (using ENV)
  1042. rpc:call(SlaveNode2, application, set_env, [syn, event_handler, syn_test_event_handler_resolution]),
  1043. rpc:call(SlaveNode2, application, set_env, [syn, scopes, [scope_all, scope_bc]]),
  1044. %% start syn on nodes
  1045. ok = syn:start(),
  1046. ok = rpc:call(SlaveNode1, syn, start, []),
  1047. ok = rpc:call(SlaveNode2, syn, start, []),
  1048. %% add custom handler for resolution (using method call)
  1049. syn:set_event_handler(syn_test_event_handler_resolution),
  1050. rpc:call(SlaveNode1, syn, set_event_handler, [syn_test_event_handler_resolution]),
  1051. %% add scopes
  1052. ok = syn:add_node_to_scopes([scope_all]),
  1053. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_all, scope_bc]]),
  1054. %% current node
  1055. TestPid = self(),
  1056. LocalNode = node(),
  1057. %% partial netsplit (1 cannot see 2)
  1058. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1059. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1060. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1061. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1062. %% start conflict processes
  1063. PidOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  1064. PidOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  1065. %% --> conflict by netsplit
  1066. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-confict-by-netsplit-custom", PidOn1, {recipient, TestPid, keepthis}]),
  1067. ok = rpc:call(SlaveNode2, syn, register, [scope_all, "proc-confict-by-netsplit-custom", PidOn2, {recipient, TestPid, "meta-2"}]),
  1068. ok = rpc:call(SlaveNode1, syn, register, [scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn1, {recipient, TestPid, keepthis}]),
  1069. ok = rpc:call(SlaveNode2, syn, register, [scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn2, {recipient, TestPid, "meta-2"}]),
  1070. %% check callbacks
  1071. syn_test_suite_helper:assert_received_messages([
  1072. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, normal},
  1073. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, normal},
  1074. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom", PidOn2, "meta-2", normal},
  1075. {on_process_registered, SlaveNode1, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, normal},
  1076. {on_process_registered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom", PidOn2, "meta-2", normal},
  1077. {on_process_registered, SlaveNode1, scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn1, keepthis, normal},
  1078. {on_process_registered, SlaveNode2, scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn2, "meta-2", normal}
  1079. ]),
  1080. %% re-join
  1081. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1082. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1083. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1084. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1085. %% retrieve
  1086. syn_test_suite_helper:assert_wait(
  1087. {PidOn1, {recipient, TestPid, keepthis}},
  1088. fun() -> syn:lookup(scope_all, "proc-confict-by-netsplit-custom") end
  1089. ),
  1090. syn_test_suite_helper:assert_wait(
  1091. {PidOn1, {recipient, TestPid, keepthis}},
  1092. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom"]) end
  1093. ),
  1094. syn_test_suite_helper:assert_wait(
  1095. {PidOn1, {recipient, TestPid, keepthis}},
  1096. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom"]) end
  1097. ),
  1098. 1 = syn:registry_count(scope_all),
  1099. 0 = syn:registry_count(scope_all, node()),
  1100. 1 = syn:registry_count(scope_all, SlaveNode1),
  1101. 0 = syn:registry_count(scope_all, SlaveNode2),
  1102. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  1103. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  1104. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  1105. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  1106. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  1107. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  1108. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  1109. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  1110. syn_test_suite_helper:assert_wait(
  1111. {PidOn1, {recipient, TestPid, keepthis}},
  1112. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "proc-confict-by-netsplit-scoped-custom"]) end
  1113. ),
  1114. syn_test_suite_helper:assert_wait(
  1115. {PidOn1, {recipient, TestPid, keepthis}},
  1116. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "proc-confict-by-netsplit-scoped-custom"]) end
  1117. ),
  1118. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc]),
  1119. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, node()]),
  1120. 1 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode1]),
  1121. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_bc, SlaveNode2]),
  1122. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc]),
  1123. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, node()]),
  1124. 1 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode1]),
  1125. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_bc, SlaveNode2]),
  1126. syn_test_suite_helper:assert_received_messages([
  1127. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom", PidOn2, "meta-2", syn_conflict_resolution},
  1128. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, syn_conflict_resolution},
  1129. {on_process_unregistered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom", PidOn2, "meta-2", syn_conflict_resolution},
  1130. {on_process_registered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, syn_conflict_resolution},
  1131. {on_process_unregistered, SlaveNode2, scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn2, "meta-2", syn_conflict_resolution},
  1132. {on_process_registered, SlaveNode2, scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn1, keepthis, syn_conflict_resolution}
  1133. ]),
  1134. %% process alive (discarded process does not get killed with a custom handler)
  1135. syn_test_suite_helper:assert_wait(
  1136. true,
  1137. fun() -> rpc:call(SlaveNode1, erlang, is_process_alive, [PidOn1]) end
  1138. ),
  1139. syn_test_suite_helper:assert_wait(
  1140. true,
  1141. fun() -> rpc:call(SlaveNode2, erlang, is_process_alive, [PidOn2]) end
  1142. ),
  1143. %% clean up default scope
  1144. syn:unregister(scope_all, "proc-confict-by-netsplit-custom"),
  1145. ok = rpc:call(SlaveNode1, syn, unregister, [scope_bc, "proc-confict-by-netsplit-scoped-custom"]),
  1146. %% retrieve
  1147. syn_test_suite_helper:assert_wait(
  1148. undefined,
  1149. fun() -> syn:lookup(scope_all, "proc-confict-by-netsplit-custom") end
  1150. ),
  1151. syn_test_suite_helper:assert_wait(
  1152. undefined,
  1153. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom"]) end
  1154. ),
  1155. syn_test_suite_helper:assert_wait(
  1156. undefined,
  1157. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom"]) end
  1158. ),
  1159. syn_test_suite_helper:assert_wait(
  1160. undefined,
  1161. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_bc, "proc-confict-by-netsplit-scoped-custom"]) end
  1162. ),
  1163. syn_test_suite_helper:assert_wait(
  1164. undefined,
  1165. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_bc, "proc-confict-by-netsplit-scoped-custom"]) end
  1166. ),
  1167. %% check callbacks
  1168. syn_test_suite_helper:assert_received_messages([
  1169. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, normal},
  1170. {on_process_unregistered, SlaveNode1, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, normal},
  1171. {on_process_unregistered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom", PidOn1, keepthis, normal},
  1172. {on_process_unregistered, SlaveNode1, scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn1, keepthis, normal},
  1173. {on_process_unregistered, SlaveNode2, scope_bc, "proc-confict-by-netsplit-scoped-custom", PidOn1, keepthis, normal}
  1174. ]),
  1175. %% --> conflict by netsplit, which returns invalid pid
  1176. %% partial netsplit (1 cannot see 2)
  1177. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1178. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1179. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1180. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1181. %% register with meta with no 'keepthis' element
  1182. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn1, {recipient, TestPid, "meta-1"}]),
  1183. ok = rpc:call(SlaveNode2, syn, register, [scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn2, {recipient, TestPid, "meta-2"}]),
  1184. %% check callbacks
  1185. syn_test_suite_helper:assert_received_messages([
  1186. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn1, "meta-1", normal},
  1187. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn1, "meta-1", normal},
  1188. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn2, "meta-2", normal},
  1189. {on_process_registered, SlaveNode1, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn1, "meta-1", normal},
  1190. {on_process_registered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn2, "meta-2", normal}
  1191. ]),
  1192. %% re-join
  1193. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1194. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1195. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1196. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1197. %% retrieve (names get freed)
  1198. syn_test_suite_helper:assert_wait(
  1199. undefined,
  1200. fun() -> syn:lookup(scope_all, "proc-confict-by-netsplit-custom-other-pid") end
  1201. ),
  1202. syn_test_suite_helper:assert_wait(
  1203. undefined,
  1204. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom-other-pid"]) end
  1205. ),
  1206. syn_test_suite_helper:assert_wait(
  1207. undefined,
  1208. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom-other-pid"]) end
  1209. ),
  1210. 0 = syn:registry_count(scope_all),
  1211. 0 = syn:registry_count(scope_all, node()),
  1212. 0 = syn:registry_count(scope_all, SlaveNode1),
  1213. 0 = syn:registry_count(scope_all, SlaveNode2),
  1214. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  1215. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  1216. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  1217. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  1218. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  1219. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  1220. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  1221. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  1222. %% check callbacks
  1223. syn_test_suite_helper:assert_received_messages([
  1224. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn2, "meta-2", syn_conflict_resolution},
  1225. {on_process_unregistered, SlaveNode1, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn1, "meta-1", syn_conflict_resolution},
  1226. {on_process_unregistered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom-other-pid", PidOn2, "meta-2", syn_conflict_resolution}
  1227. ]),
  1228. %% process alive (discarded process does not get killed with a custom handler)
  1229. syn_test_suite_helper:assert_wait(
  1230. true,
  1231. fun() -> rpc:call(SlaveNode1, erlang, is_process_alive, [PidOn1]) end
  1232. ),
  1233. syn_test_suite_helper:assert_wait(
  1234. true,
  1235. fun() -> rpc:call(SlaveNode2, erlang, is_process_alive, [PidOn2]) end
  1236. ),
  1237. %% --> conflict by netsplit, which crashes
  1238. %% partial netsplit (1 cannot see 2)
  1239. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1240. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1241. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1242. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1243. %% register with meta with no 'crash' element
  1244. ok = rpc:call(SlaveNode1, syn, register, [scope_all, "proc-confict-by-netsplit-custom-crash", PidOn1, {recipient, TestPid, crash}]),
  1245. ok = rpc:call(SlaveNode2, syn, register, [scope_all, "proc-confict-by-netsplit-custom-crash", PidOn2, {recipient, TestPid, crash}]),
  1246. %% check callbacks
  1247. syn_test_suite_helper:assert_received_messages([
  1248. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn1, crash, normal},
  1249. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn1, crash, normal},
  1250. {on_process_registered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn2, crash, normal},
  1251. {on_process_registered, SlaveNode1, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn1, crash, normal},
  1252. {on_process_registered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn2, crash, normal}
  1253. ]),
  1254. %% re-join
  1255. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1256. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1257. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1258. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1259. %% retrieve (names get freed)
  1260. syn_test_suite_helper:assert_wait(
  1261. undefined,
  1262. fun() -> syn:lookup(scope_all, "proc-confict-by-netsplit-custom-crash") end
  1263. ),
  1264. syn_test_suite_helper:assert_wait(
  1265. undefined,
  1266. fun() -> rpc:call(SlaveNode1, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom-crash"]) end
  1267. ),
  1268. syn_test_suite_helper:assert_wait(
  1269. undefined,
  1270. fun() -> rpc:call(SlaveNode2, syn, lookup, [scope_all, "proc-confict-by-netsplit-custom-crash"]) end
  1271. ),
  1272. 0 = syn:registry_count(scope_all),
  1273. 0 = syn:registry_count(scope_all, node()),
  1274. 0 = syn:registry_count(scope_all, SlaveNode1),
  1275. 0 = syn:registry_count(scope_all, SlaveNode2),
  1276. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all]),
  1277. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, node()]),
  1278. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode1]),
  1279. 0 = rpc:call(SlaveNode1, syn, registry_count, [scope_all, SlaveNode2]),
  1280. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all]),
  1281. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, node()]),
  1282. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode1]),
  1283. 0 = rpc:call(SlaveNode2, syn, registry_count, [scope_all, SlaveNode2]),
  1284. %% check callbacks
  1285. syn_test_suite_helper:assert_received_messages([
  1286. {on_process_unregistered, LocalNode, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn2, crash, syn_conflict_resolution},
  1287. {on_process_unregistered, SlaveNode1, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn1, crash, syn_conflict_resolution},
  1288. {on_process_unregistered, SlaveNode2, scope_all, "proc-confict-by-netsplit-custom-crash", PidOn2, crash, syn_conflict_resolution}
  1289. ]),
  1290. %% process alive (discarded process does not get killed with a custom handler)
  1291. syn_test_suite_helper:assert_wait(
  1292. true,
  1293. fun() -> rpc:call(SlaveNode1, erlang, is_process_alive, [PidOn1]) end
  1294. ),
  1295. syn_test_suite_helper:assert_wait(
  1296. true,
  1297. fun() -> rpc:call(SlaveNode2, erlang, is_process_alive, [PidOn2]) end
  1298. ).
  1299. four_nodes_concurrency(Config) ->
  1300. %% get slaves
  1301. SlaveNode1 = proplists:get_value(syn_slave_1, Config),
  1302. SlaveNode2 = proplists:get_value(syn_slave_2, Config),
  1303. SlaveNode3 = proplists:get_value(syn_slave_3, Config),
  1304. %% start syn on nodes
  1305. ok = syn:start(),
  1306. ok = rpc:call(SlaveNode1, syn, start, []),
  1307. ok = rpc:call(SlaveNode2, syn, start, []),
  1308. ok = rpc:call(SlaveNode3, syn, start, []),
  1309. %% add scopes
  1310. ok = syn:add_node_to_scopes([scope_all]),
  1311. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[scope_all]]),
  1312. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[scope_all]]),
  1313. ok = rpc:call(SlaveNode3, syn, add_node_to_scopes, [[scope_all]]),
  1314. %% ref
  1315. TestPid = self(),
  1316. Iterations = 250,
  1317. %% concurrent test
  1318. WorkerFun = fun() ->
  1319. lists:foreach(fun(_) ->
  1320. %% start pid
  1321. Pid = syn_test_suite_helper:start_process(),
  1322. RandomMeta = rand:uniform(99999),
  1323. %% loop
  1324. case syn:register(scope_all, <<"concurrent">>, Pid, RandomMeta) of
  1325. ok ->
  1326. ok;
  1327. {error, taken} ->
  1328. case syn:unregister(scope_all, <<"concurrent">>) of
  1329. {error, undefined} ->
  1330. ok;
  1331. {error, race_condition} ->
  1332. ok;
  1333. ok ->
  1334. syn:register(scope_all, <<"concurrent">>, Pid, RandomMeta)
  1335. end
  1336. end,
  1337. %% random kill
  1338. case rand:uniform(10) of
  1339. 1 -> exit(Pid, kill);
  1340. _ -> ok
  1341. end,
  1342. %% random sleep
  1343. RndTime = rand:uniform(30),
  1344. timer:sleep(RndTime)
  1345. end, lists:seq(1, Iterations)),
  1346. TestPid ! {done, node()}
  1347. end,
  1348. %% spawn concurrent
  1349. LocalNode = node(),
  1350. spawn(LocalNode, WorkerFun),
  1351. spawn(SlaveNode1, WorkerFun),
  1352. spawn(SlaveNode2, WorkerFun),
  1353. spawn(SlaveNode3, WorkerFun),
  1354. %% wait for workers done
  1355. syn_test_suite_helper:assert_received_messages([
  1356. {done, LocalNode},
  1357. {done, SlaveNode1},
  1358. {done, SlaveNode2},
  1359. {done, SlaveNode3}
  1360. ]),
  1361. %% check results are same across network
  1362. syn_test_suite_helper:assert_wait(
  1363. 1,
  1364. fun() ->
  1365. ResultPidLocal = syn:lookup(scope_all, <<"concurrent">>),
  1366. ResultPidOn1 = rpc:call(SlaveNode1, syn, lookup, [scope_all, <<"concurrent">>]),
  1367. ResultPidOn2 = rpc:call(SlaveNode2, syn, lookup, [scope_all, <<"concurrent">>]),
  1368. ResultPidOn3 = rpc:call(SlaveNode3, syn, lookup, [scope_all, <<"concurrent">>]),
  1369. %% if unique set is of 1 element then they all contain the same result
  1370. Ordset = ordsets:from_list([ResultPidLocal, ResultPidOn1, ResultPidOn2, ResultPidOn3]),
  1371. ordsets:size(Ordset)
  1372. end
  1373. ).
  1374. %% ===================================================================
  1375. %% Internal
  1376. %% ===================================================================
  1377. add_to_local_table(Scope, Name, Pid, Meta, Time, MRef) ->
  1378. TableByName = syn_backbone:get_table_name(syn_registry_by_name, Scope),
  1379. TableByPid = syn_backbone:get_table_name(syn_registry_by_pid, Scope),
  1380. syn_registry:add_to_local_table(Name, Pid, Meta, Time, MRef, TableByName, TableByPid).
  1381. remove_from_local_table(Scope, Name, Pid) ->
  1382. TableByName = syn_backbone:get_table_name(syn_registry_by_name, Scope),
  1383. TableByPid = syn_backbone:get_table_name(syn_registry_by_pid, Scope),
  1384. syn_registry:remove_from_local_table(Name, Pid, TableByName, TableByPid).