syn_registry_SUITE.erl 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. %% ==========================================================================================================
  2. %% Syn - A global Process Registry and Process Group manager.
  3. %%
  4. %% The MIT License (MIT)
  5. %%
  6. %% Copyright (c) 2015-2019 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. single_node_register_and_monitor/1,
  35. single_node_register_and_unregister/1,
  36. single_node_registration_errors/1,
  37. single_node_registry_count/1,
  38. single_node_register_gen_server/1,
  39. single_node_callback_on_process_exit/1,
  40. single_node_ensure_callback_process_exit_is_called_if_process_killed/1,
  41. single_node_monitor_after_registry_crash/1
  42. ]).
  43. -export([
  44. two_nodes_register_monitor_and_unregister/1,
  45. two_nodes_registry_count/1,
  46. two_nodes_registration_race_condition_conflict_resolution_keep_local/1,
  47. two_nodes_registration_race_condition_conflict_resolution_keep_remote/1,
  48. two_nodes_registration_race_condition_conflict_resolution_when_process_died/1,
  49. two_nodes_registry_full_cluster_sync_on_boot_node_added_later/1,
  50. two_nodes_registry_full_cluster_sync_on_boot_syn_started_later/1
  51. ]).
  52. -export([
  53. three_nodes_partial_netsplit_consistency/1,
  54. three_nodes_full_netsplit_consistency/1,
  55. three_nodes_start_syn_before_connecting_cluster_with_conflict/1,
  56. three_nodes_start_syn_before_connecting_cluster_with_custom_conflict_resolution/1,
  57. three_nodes_registration_race_condition_custom_conflict_resolution/1,
  58. three_nodes_anti_entropy/1,
  59. three_nodes_anti_entropy_manual/1
  60. ]).
  61. %% support
  62. -export([
  63. start_syn_delayed_and_register_local_process/3,
  64. start_syn_delayed_with_custom_handler_register_local_process/4
  65. ]).
  66. %% include
  67. -include_lib("common_test/include/ct.hrl").
  68. -include_lib("../src/syn.hrl").
  69. %% ===================================================================
  70. %% Callbacks
  71. %% ===================================================================
  72. %% -------------------------------------------------------------------
  73. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  74. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  75. %% GroupName = atom()
  76. %% TestCase = atom()
  77. %% Reason = any()
  78. %% -------------------------------------------------------------------
  79. all() ->
  80. [
  81. {group, single_node_process_registration},
  82. {group, two_nodes_process_registration},
  83. {group, three_nodes_process_registration}
  84. ].
  85. %% -------------------------------------------------------------------
  86. %% Function: groups() -> [Group]
  87. %% Group = {GroupName,Properties,GroupsAndTestCases}
  88. %% GroupName = atom()
  89. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  90. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  91. %% TestCase = atom()
  92. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  93. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  94. %% repeat_until_any_ok | repeat_until_any_fail
  95. %% N = integer() | forever
  96. %% -------------------------------------------------------------------
  97. groups() ->
  98. [
  99. {single_node_process_registration, [shuffle], [
  100. single_node_register_and_monitor,
  101. single_node_register_and_unregister,
  102. single_node_registration_errors,
  103. single_node_registry_count,
  104. single_node_register_gen_server,
  105. single_node_callback_on_process_exit,
  106. single_node_ensure_callback_process_exit_is_called_if_process_killed,
  107. single_node_monitor_after_registry_crash
  108. ]},
  109. {two_nodes_process_registration, [shuffle], [
  110. two_nodes_register_monitor_and_unregister,
  111. two_nodes_registry_count,
  112. two_nodes_registration_race_condition_conflict_resolution_keep_local,
  113. two_nodes_registration_race_condition_conflict_resolution_keep_remote,
  114. two_nodes_registration_race_condition_conflict_resolution_when_process_died,
  115. two_nodes_registry_full_cluster_sync_on_boot_node_added_later,
  116. two_nodes_registry_full_cluster_sync_on_boot_syn_started_later
  117. ]},
  118. {three_nodes_process_registration, [shuffle], [
  119. three_nodes_partial_netsplit_consistency,
  120. three_nodes_full_netsplit_consistency,
  121. three_nodes_start_syn_before_connecting_cluster_with_conflict,
  122. three_nodes_start_syn_before_connecting_cluster_with_custom_conflict_resolution,
  123. three_nodes_registration_race_condition_custom_conflict_resolution,
  124. three_nodes_anti_entropy,
  125. three_nodes_anti_entropy_manual
  126. ]}
  127. ].
  128. %% -------------------------------------------------------------------
  129. %% Function: init_per_suite(Config0) ->
  130. %% Config1 | {skip,Reason} |
  131. %% {skip_and_save,Reason,Config1}
  132. %% Config0 = Config1 = [tuple()]
  133. %% Reason = any()
  134. %% -------------------------------------------------------------------
  135. init_per_suite(Config) ->
  136. Config.
  137. %% -------------------------------------------------------------------
  138. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  139. %% Config0 = Config1 = [tuple()]
  140. %% -------------------------------------------------------------------
  141. end_per_suite(_Config) ->
  142. ok.
  143. %% -------------------------------------------------------------------
  144. %% Function: init_per_group(GroupName, Config0) ->
  145. %% Config1 | {skip,Reason} |
  146. %% {skip_and_save,Reason,Config1}
  147. %% GroupName = atom()
  148. %% Config0 = Config1 = [tuple()]
  149. %% Reason = any()
  150. %% -------------------------------------------------------------------
  151. init_per_group(two_nodes_process_registration, Config) ->
  152. %% start slave
  153. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  154. %% config
  155. [{slave_node, SlaveNode} | Config];
  156. init_per_group(three_nodes_process_registration, Config) ->
  157. %% start slave
  158. {ok, SlaveNode1} = syn_test_suite_helper:start_slave(syn_slave_1),
  159. {ok, SlaveNode2} = syn_test_suite_helper:start_slave(syn_slave_2),
  160. %% config
  161. [{slave_node_1, SlaveNode1}, {slave_node_2, SlaveNode2} | Config];
  162. init_per_group(_GroupName, Config) ->
  163. Config.
  164. %% -------------------------------------------------------------------
  165. %% Function: end_per_group(GroupName, Config0) ->
  166. %% void() | {save_config,Config1}
  167. %% GroupName = atom()
  168. %% Config0 = Config1 = [tuple()]
  169. %% -------------------------------------------------------------------
  170. end_per_group(two_nodes_process_registration, Config) ->
  171. SlaveNode = proplists:get_value(slave_node, Config),
  172. syn_test_suite_helper:connect_node(SlaveNode),
  173. syn_test_suite_helper:clean_after_test(),
  174. syn_test_suite_helper:stop_slave(syn_slave),
  175. timer:sleep(1000);
  176. end_per_group(three_nodes_process_registration, Config) ->
  177. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  178. syn_test_suite_helper:connect_node(SlaveNode1),
  179. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  180. syn_test_suite_helper:connect_node(SlaveNode2),
  181. syn_test_suite_helper:clean_after_test(),
  182. syn_test_suite_helper:stop_slave(syn_slave_1),
  183. syn_test_suite_helper:stop_slave(syn_slave_2),
  184. timer:sleep(1000);
  185. end_per_group(_GroupName, _Config) ->
  186. syn_test_suite_helper:clean_after_test().
  187. %% -------------------------------------------------------------------
  188. %% Function: init_per_testcase(TestCase, Config0) ->
  189. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  190. %% TestCase = atom()
  191. %% Config0 = Config1 = [tuple()]
  192. %% Reason = any()
  193. %% -------------------------------------------------------------------
  194. init_per_testcase(_TestCase, Config) ->
  195. Config.
  196. %% -------------------------------------------------------------------
  197. %% Function: end_per_testcase(TestCase, Config0) ->
  198. %% void() | {save_config,Config1} | {fail,Reason}
  199. %% TestCase = atom()
  200. %% Config0 = Config1 = [tuple()]
  201. %% Reason = any()
  202. %% -------------------------------------------------------------------
  203. end_per_testcase(_, _Config) ->
  204. syn_test_suite_helper:clean_after_test().
  205. %% ===================================================================
  206. %% Tests
  207. %% ===================================================================
  208. single_node_register_and_monitor(_Config) ->
  209. %% start
  210. ok = syn:start(),
  211. %% start processes
  212. Pid = syn_test_suite_helper:start_process(),
  213. PidWithMeta = syn_test_suite_helper:start_process(),
  214. %% retrieve
  215. undefined = syn:whereis(<<"my proc">>),
  216. %% register
  217. ok = syn:register(<<"my proc">>, Pid),
  218. ok = syn:register({"my proc 2"}, Pid),
  219. ok = syn:register(<<"my proc with meta">>, PidWithMeta, {meta, <<"meta">>}),
  220. %% retrieve
  221. Pid = syn:whereis(<<"my proc">>),
  222. Pid = syn:whereis({"my proc 2"}),
  223. {PidWithMeta, {meta, <<"meta">>}} = syn:whereis(<<"my proc with meta">>, with_meta),
  224. %% re-register
  225. ok = syn:register(<<"my proc with meta">>, PidWithMeta, {meta2, <<"meta2">>}),
  226. {PidWithMeta, {meta2, <<"meta2">>}} = syn:whereis(<<"my proc with meta">>, with_meta),
  227. %% kill process
  228. syn_test_suite_helper:kill_process(Pid),
  229. syn_test_suite_helper:kill_process(PidWithMeta),
  230. timer:sleep(100),
  231. %% retrieve
  232. undefined = syn:whereis(<<"my proc">>),
  233. undefined = syn:whereis({"my proc 2"}),
  234. undefined = syn:whereis(<<"my proc with meta">>).
  235. single_node_register_and_unregister(_Config) ->
  236. %% start
  237. ok = syn:start(),
  238. %% start process
  239. Pid = syn_test_suite_helper:start_process(),
  240. %% retrieve
  241. undefined = syn:whereis(<<"my proc">>),
  242. %% register
  243. ok = syn:register(<<"my proc">>, Pid),
  244. ok = syn:register(<<"my proc 2">>, Pid),
  245. %% retrieve
  246. Pid = syn:whereis(<<"my proc">>),
  247. Pid = syn:whereis(<<"my proc 2">>),
  248. %% unregister 1
  249. ok = syn:unregister(<<"my proc">>),
  250. %% retrieve
  251. undefined = syn:whereis(<<"my proc">>),
  252. Pid = syn:whereis(<<"my proc 2">>),
  253. %% unregister 2
  254. ok = syn:unregister(<<"my proc 2">>),
  255. {error, undefined} = syn:unregister(<<"my proc 2">>),
  256. %% retrieve
  257. undefined = syn:whereis(<<"my proc">>),
  258. undefined = syn:whereis(<<"my proc 2">>).
  259. single_node_registration_errors(_Config) ->
  260. %% start
  261. ok = syn:start(),
  262. %% start process
  263. Pid = syn_test_suite_helper:start_process(),
  264. Pid2 = syn_test_suite_helper:start_process(),
  265. %% register
  266. ok = syn:register(<<"my proc">>, Pid),
  267. {error, taken} = syn:register(<<"my proc">>, Pid2),
  268. %% kill processes
  269. syn_test_suite_helper:kill_process(Pid),
  270. syn_test_suite_helper:kill_process(Pid2),
  271. timer:sleep(100),
  272. %% retrieve
  273. undefined = syn:whereis(<<"my proc">>),
  274. %% try registering a dead pid
  275. {error, not_alive} = syn:register(<<"my proc">>, Pid).
  276. single_node_registry_count(_Config) ->
  277. %% start
  278. ok = syn:start(),
  279. %% start process
  280. Pid = syn_test_suite_helper:start_process(),
  281. Pid2 = syn_test_suite_helper:start_process(),
  282. PidUnregistered = syn_test_suite_helper:start_process(),
  283. %% register
  284. ok = syn:register(<<"my proc">>, Pid),
  285. ok = syn:register(<<"my proc 2">>, Pid2),
  286. %% count
  287. 2 = syn:registry_count(),
  288. 2 = syn:registry_count(node()),
  289. %% kill & unregister
  290. syn_test_suite_helper:kill_process(Pid),
  291. ok = syn:unregister(<<"my proc 2">>),
  292. syn_test_suite_helper:kill_process(PidUnregistered),
  293. timer:sleep(100),
  294. %% count
  295. 0 = syn:registry_count(),
  296. 0 = syn:registry_count(node()).
  297. single_node_register_gen_server(_Config) ->
  298. %% start
  299. ok = syn:start(),
  300. %% start gen server via syn
  301. {ok, Pid} = syn_test_gen_server:start_link(),
  302. %% retrieve
  303. Pid = syn:whereis(syn_test_gen_server),
  304. %% call
  305. pong = syn_test_gen_server:ping(),
  306. %% send via syn
  307. syn:send(syn_test_gen_server, {self(), send_ping}),
  308. receive
  309. send_pong -> ok
  310. after 1000 ->
  311. ok = did_not_receive_gen_server_pong
  312. end,
  313. %% stop server
  314. syn_test_gen_server:stop(),
  315. timer:sleep(200),
  316. %% retrieve
  317. undefined = syn:whereis(syn_test_gen_server),
  318. %% send via syn
  319. {badarg, {syn_test_gen_server, anything}} = (catch syn:send(syn_test_gen_server, anything)).
  320. single_node_callback_on_process_exit(_Config) ->
  321. %% use custom handler
  322. syn_test_suite_helper:use_custom_handler(),
  323. %% start
  324. ok = syn:start(),
  325. %% start process
  326. Pid = syn_test_suite_helper:start_process(),
  327. Pid2 = syn_test_suite_helper:start_process(),
  328. %% register
  329. TestPid = self(),
  330. ok = syn:register(<<"my proc">>, Pid, {pid, TestPid}),
  331. ok = syn:register(<<"my proc - alternate">>, Pid, {pid_alternate, TestPid}),
  332. ok = syn:register(<<"my proc 2">>, Pid2, {pid2, TestPid}),
  333. %% kill 1
  334. syn_test_suite_helper:kill_process(Pid),
  335. receive
  336. {received_event_on, pid} ->
  337. ok;
  338. {received_event_on, pid2} ->
  339. ok = callback_on_process_exit_was_received_by_pid2
  340. after 1000 ->
  341. ok = callback_on_process_exit_was_not_received_by_pid
  342. end,
  343. receive
  344. {received_event_on, pid_alternate} ->
  345. ok;
  346. {received_event_on, pid2} ->
  347. ok = callback_on_process_exit_was_received_by_pid2
  348. after 1000 ->
  349. ok = callback_on_process_exit_was_not_received_by_pid
  350. end,
  351. %% unregister & kill 2
  352. ok = syn:unregister(<<"my proc 2">>),
  353. syn_test_suite_helper:kill_process(Pid2),
  354. receive
  355. {received_event_on, pid2} ->
  356. ok = callback_on_process_exit_was_received_by_pid2
  357. after 1000 ->
  358. ok
  359. end.
  360. single_node_ensure_callback_process_exit_is_called_if_process_killed(_Config) ->
  361. Name = <<"my proc">>,
  362. %% use custom handler
  363. syn_test_suite_helper:use_custom_handler(),
  364. %% start
  365. ok = syn:start(),
  366. %% start process
  367. Pid = syn_test_suite_helper:start_process(),
  368. %% register
  369. TestPid = self(),
  370. ok = syn:register(Name, Pid, {some_meta, TestPid}),
  371. %% remove from table to simulate conflict resolution
  372. syn_registry:remove_from_local_table(Name),
  373. %% kill
  374. exit(Pid, {syn_resolve_kill, Name, {some_meta, TestPid}}),
  375. receive
  376. {received_event_on, some_meta} ->
  377. ok
  378. after 1000 ->
  379. ok = callback_on_process_exit_was_not_received_by_pid
  380. end.
  381. single_node_monitor_after_registry_crash(_Config) ->
  382. %% start
  383. ok = syn:start(),
  384. %% start processes
  385. Pid = syn_test_suite_helper:start_process(),
  386. %% register
  387. ok = syn:register(<<"my proc">>, Pid),
  388. %% kill registry
  389. exit(whereis(syn_registry), kill),
  390. timer:sleep(200),
  391. %% retrieve
  392. Pid = syn:whereis(<<"my proc">>),
  393. %% kill process
  394. syn_test_suite_helper:kill_process(Pid),
  395. timer:sleep(200),
  396. %% retrieve
  397. undefined = syn:whereis(<<"my proc 2">>).
  398. two_nodes_register_monitor_and_unregister(Config) ->
  399. %% get slave
  400. SlaveNode = proplists:get_value(slave_node, Config),
  401. %% start
  402. ok = syn:start(),
  403. ok = rpc:call(SlaveNode, syn, start, []),
  404. timer:sleep(100),
  405. %% start processes
  406. LocalPid = syn_test_suite_helper:start_process(),
  407. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  408. RemotePidRegRemote = syn_test_suite_helper:start_process(SlaveNode),
  409. %% retrieve
  410. undefined = syn:whereis(<<"local proc">>),
  411. undefined = syn:whereis(<<"remote proc">>),
  412. undefined = syn:whereis(<<"remote proc reg_remote">>),
  413. undefined = rpc:call(SlaveNode, syn, whereis, [<<"local proc">>]),
  414. undefined = rpc:call(SlaveNode, syn, whereis, [<<"remote proc">>]),
  415. undefined = rpc:call(SlaveNode, syn, whereis, [<<"remote proc reg_remote">>]),
  416. %% register
  417. ok = syn:register(<<"local proc">>, LocalPid),
  418. ok = syn:register(<<"remote proc">>, RemotePid),
  419. ok = rpc:call(SlaveNode, syn, register, [<<"remote proc reg_remote">>, RemotePidRegRemote]),
  420. timer:sleep(500),
  421. %% retrieve
  422. LocalPid = syn:whereis(<<"local proc">>),
  423. RemotePid = syn:whereis(<<"remote proc">>),
  424. RemotePidRegRemote = syn:whereis(<<"remote proc reg_remote">>),
  425. LocalPid = rpc:call(SlaveNode, syn, whereis, [<<"local proc">>]),
  426. RemotePid = rpc:call(SlaveNode, syn, whereis, [<<"remote proc">>]),
  427. RemotePidRegRemote = rpc:call(SlaveNode, syn, whereis, [<<"remote proc reg_remote">>]),
  428. %% kill & unregister processes
  429. syn_test_suite_helper:kill_process(LocalPid),
  430. ok = syn:unregister(<<"remote proc">>),
  431. syn_test_suite_helper:kill_process(RemotePidRegRemote),
  432. timer:sleep(100),
  433. %% retrieve
  434. undefined = syn:whereis(<<"local proc">>),
  435. undefined = syn:whereis(<<"remote proc">>),
  436. undefined = syn:whereis(<<"remote proc reg_remote">>),
  437. undefined = rpc:call(SlaveNode, syn, whereis, [<<"local proc">>]),
  438. undefined = rpc:call(SlaveNode, syn, whereis, [<<"remote proc">>]),
  439. undefined = rpc:call(SlaveNode, syn, whereis, [<<"remote proc reg_remote">>]).
  440. two_nodes_registry_count(Config) ->
  441. %% get slave
  442. SlaveNode = proplists:get_value(slave_node, Config),
  443. %% start
  444. ok = syn:start(),
  445. ok = rpc:call(SlaveNode, syn, start, []),
  446. timer:sleep(100),
  447. %% start processes
  448. LocalPid = syn_test_suite_helper:start_process(),
  449. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  450. RemotePidRegRemote = syn_test_suite_helper:start_process(SlaveNode),
  451. _PidUnregistered = syn_test_suite_helper:start_process(),
  452. %% register
  453. ok = syn:register(<<"local proc">>, LocalPid),
  454. ok = syn:register(<<"remote proc">>, RemotePid),
  455. ok = rpc:call(SlaveNode, syn, register, [<<"remote proc reg_remote">>, RemotePidRegRemote]),
  456. timer:sleep(500),
  457. %% count
  458. 3 = syn:registry_count(),
  459. 1 = syn:registry_count(node()),
  460. 2 = syn:registry_count(SlaveNode),
  461. %% kill & unregister processes
  462. syn_test_suite_helper:kill_process(LocalPid),
  463. ok = syn:unregister(<<"remote proc">>),
  464. syn_test_suite_helper:kill_process(RemotePidRegRemote),
  465. timer:sleep(100),
  466. %% count
  467. 0 = syn:registry_count(),
  468. 0 = syn:registry_count(node()),
  469. 0 = syn:registry_count(SlaveNode).
  470. two_nodes_registration_race_condition_conflict_resolution_keep_local(Config) ->
  471. ConflictingName = "COMMON",
  472. %% get slaves
  473. SlaveNode = proplists:get_value(slave_node, Config),
  474. %% start syn on nodes
  475. ok = syn:start(),
  476. ok = rpc:call(SlaveNode, syn, start, []),
  477. timer:sleep(1000),
  478. %% start processes
  479. Pid0 = syn_test_suite_helper:start_process(),
  480. Pid1 = syn_test_suite_helper:start_process(SlaveNode),
  481. %% inject into syn to simulate concurrent registration
  482. ok = syn_registry:add_to_local_table(ConflictingName, Pid0, node(), undefined),
  483. %% register on slave node to trigger conflict resolution on master node
  484. ok = rpc:call(SlaveNode, syn, register, [ConflictingName, Pid1, SlaveNode]),
  485. timer:sleep(1000),
  486. %% check metadata, resolution happens on master node
  487. Node = node(),
  488. {Pid0, Node} = syn:whereis(ConflictingName, with_meta),
  489. {Pid0, Node} = rpc:call(SlaveNode, syn, whereis, [ConflictingName, with_meta]),
  490. %% check that other processes are not alive because syn killed them
  491. true = is_process_alive(Pid0),
  492. false = rpc:call(SlaveNode, erlang, is_process_alive, [Pid1]).
  493. two_nodes_registration_race_condition_conflict_resolution_keep_remote(Config) ->
  494. ConflictingName = "COMMON",
  495. %% get slaves
  496. SlaveNode = proplists:get_value(slave_node, Config),
  497. %% use customer handler
  498. syn_test_suite_helper:use_custom_handler(),
  499. rpc:call(SlaveNode, syn_test_suite_helper, use_custom_handler, []),
  500. %% start syn on nodes
  501. ok = syn:start(),
  502. ok = rpc:call(SlaveNode, syn, start, []),
  503. timer:sleep(1000),
  504. %% start processes
  505. Pid0 = syn_test_suite_helper:start_process(),
  506. Pid1 = syn_test_suite_helper:start_process(SlaveNode),
  507. %% inject into syn to simulate concurrent registration
  508. ok = syn_registry:add_to_local_table(ConflictingName, Pid0, node(), undefined),
  509. %% register on slave node to trigger conflict resolution on master node
  510. ok = rpc:call(SlaveNode, syn, register, [ConflictingName, Pid1, keep_this_one]),
  511. timer:sleep(1000),
  512. %% check metadata, resolution happens on master node
  513. {Pid1, keep_this_one} = syn:whereis(ConflictingName, with_meta),
  514. {Pid1, keep_this_one} = rpc:call(SlaveNode, syn, whereis, [ConflictingName, with_meta]),
  515. %% check that other processes are not alive because syn killed them
  516. true = is_process_alive(Pid0),
  517. true = rpc:call(SlaveNode, erlang, is_process_alive, [Pid1]).
  518. two_nodes_registration_race_condition_conflict_resolution_when_process_died(Config) ->
  519. ConflictingName = "COMMON",
  520. %% get slaves
  521. SlaveNode = proplists:get_value(slave_node, Config),
  522. %% use customer handler
  523. syn_test_suite_helper:use_custom_handler(),
  524. rpc:call(SlaveNode, syn_test_suite_helper, use_custom_handler, []),
  525. %% start syn on nodes
  526. ok = syn:start(),
  527. ok = rpc:call(SlaveNode, syn, start, []),
  528. timer:sleep(100),
  529. %% start processes
  530. Pid0 = syn_test_suite_helper:start_process(),
  531. Pid1 = syn_test_suite_helper:start_process(SlaveNode),
  532. %% inject into syn to simulate concurrent registration
  533. syn_registry:add_to_local_table(ConflictingName, Pid0, keep_this_one, undefined),
  534. %% kill process
  535. syn_test_suite_helper:kill_process(Pid0),
  536. %% register to trigger conflict resolution
  537. ok = rpc:call(SlaveNode, syn, register, [ConflictingName, Pid1, SlaveNode]),
  538. timer:sleep(1000),
  539. %% check
  540. {Pid1, SlaveNode} = syn:whereis(ConflictingName, with_meta),
  541. {Pid1, SlaveNode} = rpc:call(SlaveNode, syn, whereis, [ConflictingName, with_meta]),
  542. %% check that process is alive
  543. true = rpc:call(SlaveNode, erlang, is_process_alive, [Pid1]).
  544. two_nodes_registry_full_cluster_sync_on_boot_node_added_later(_Config) ->
  545. %% stop slave
  546. syn_test_suite_helper:stop_slave(syn_slave),
  547. %% start syn on local node
  548. ok = syn:start(),
  549. %% start process
  550. Pid = syn_test_suite_helper:start_process(),
  551. %% register
  552. ok = syn:register(<<"proc">>, Pid),
  553. %% start remote node and syn
  554. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  555. ok = rpc:call(SlaveNode, syn, start, []),
  556. timer:sleep(1000),
  557. %% check
  558. Pid = syn:whereis(<<"proc">>),
  559. Pid = rpc:call(SlaveNode, syn, whereis, [<<"proc">>]).
  560. two_nodes_registry_full_cluster_sync_on_boot_syn_started_later(Config) ->
  561. %% get slaves
  562. SlaveNode = proplists:get_value(slave_node, Config),
  563. %% start syn on local node
  564. ok = syn:start(),
  565. %% start process
  566. Pid = syn_test_suite_helper:start_process(),
  567. %% register
  568. ok = syn:register(<<"proc">>, Pid),
  569. %% start ib remote syn
  570. ok = rpc:call(SlaveNode, syn, start, []),
  571. timer:sleep(500),
  572. %% check
  573. Pid = syn:whereis(<<"proc">>),
  574. Pid = rpc:call(SlaveNode, syn, whereis, [<<"proc">>]).
  575. three_nodes_partial_netsplit_consistency(Config) ->
  576. %% get slaves
  577. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  578. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  579. %% start syn on nodes
  580. ok = syn:start(),
  581. ok = rpc:call(SlaveNode1, syn, start, []),
  582. ok = rpc:call(SlaveNode2, syn, start, []),
  583. timer:sleep(100),
  584. %% start processes
  585. Pid0 = syn_test_suite_helper:start_process(),
  586. Pid0Changed = syn_test_suite_helper:start_process(),
  587. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  588. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  589. timer:sleep(100),
  590. %% retrieve
  591. undefined = syn:whereis(<<"proc0">>),
  592. undefined = syn:whereis(<<"proc0-changed">>),
  593. undefined = syn:whereis(<<"proc1">>),
  594. undefined = syn:whereis(<<"proc2">>),
  595. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  596. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  597. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  598. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  599. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
  600. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
  601. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
  602. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
  603. %% register (mix nodes)
  604. ok = rpc:call(SlaveNode2, syn, register, [<<"proc0">>, Pid0]),
  605. ok = syn:register(<<"proc1">>, Pid1),
  606. ok = rpc:call(SlaveNode1, syn, register, [<<"proc2">>, Pid2]),
  607. ok = rpc:call(SlaveNode1, syn, register, [<<"proc0-changed">>, Pid0Changed]),
  608. timer:sleep(200),
  609. %% retrieve
  610. Pid0 = syn:whereis(<<"proc0">>),
  611. Pid0Changed = syn:whereis(<<"proc0-changed">>),
  612. Pid1 = syn:whereis(<<"proc1">>),
  613. Pid2 = syn:whereis(<<"proc2">>),
  614. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  615. Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  616. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  617. Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  618. Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
  619. Pid0Changed = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
  620. Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
  621. Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
  622. %% disconnect slave 2 from main (slave 1 can still see slave 2)
  623. syn_test_suite_helper:disconnect_node(SlaveNode2),
  624. timer:sleep(500),
  625. %% retrieve
  626. Pid0 = syn:whereis(<<"proc0">>),
  627. Pid0Changed = syn:whereis(<<"proc0-changed">>),
  628. Pid1 = syn:whereis(<<"proc1">>),
  629. undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
  630. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  631. Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  632. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  633. Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]), %% slave 1 still has slave 2 so 'proc2' is still there
  634. %% disconnect slave 1
  635. syn_test_suite_helper:disconnect_node(SlaveNode1),
  636. timer:sleep(500),
  637. %% unregister proc0-changed
  638. ok = syn:unregister(<<"proc0-changed">>),
  639. %% retrieve
  640. Pid0 = syn:whereis(<<"proc0">>),
  641. undefined = syn:whereis(<<"proc0-changed">>),
  642. undefined = syn:whereis(<<"proc1">>),
  643. undefined = syn:whereis(<<"proc2">>),
  644. %% reconnect all
  645. syn_test_suite_helper:connect_node(SlaveNode1),
  646. syn_test_suite_helper:connect_node(SlaveNode2),
  647. timer:sleep(5000),
  648. %% retrieve
  649. Pid0 = syn:whereis(<<"proc0">>),
  650. undefined = syn:whereis(<<"proc0-changed">>),
  651. Pid1 = syn:whereis(<<"proc1">>),
  652. Pid2 = syn:whereis(<<"proc2">>),
  653. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  654. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  655. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  656. Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  657. Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
  658. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
  659. Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
  660. Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]).
  661. three_nodes_full_netsplit_consistency(Config) ->
  662. %% get slaves
  663. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  664. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  665. %% start syn on nodes
  666. ok = syn:start(),
  667. ok = rpc:call(SlaveNode1, syn, start, []),
  668. ok = rpc:call(SlaveNode2, syn, start, []),
  669. timer:sleep(100),
  670. %% start processes
  671. Pid0 = syn_test_suite_helper:start_process(),
  672. Pid0Changed = syn_test_suite_helper:start_process(),
  673. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  674. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  675. timer:sleep(100),
  676. %% retrieve
  677. undefined = syn:whereis(<<"proc0">>),
  678. undefined = syn:whereis(<<"proc0-changed">>),
  679. undefined = syn:whereis(<<"proc1">>),
  680. undefined = syn:whereis(<<"proc2">>),
  681. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  682. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  683. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  684. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  685. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
  686. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
  687. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
  688. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
  689. %% register (mix nodes)
  690. ok = rpc:call(SlaveNode2, syn, register, [<<"proc0">>, Pid0]),
  691. ok = rpc:call(SlaveNode2, syn, register, [<<"proc0-changed">>, Pid0Changed]),
  692. ok = syn:register(<<"proc1">>, Pid1),
  693. ok = rpc:call(SlaveNode1, syn, register, [<<"proc2">>, Pid2]),
  694. timer:sleep(200),
  695. %% retrieve
  696. Pid0 = syn:whereis(<<"proc0">>),
  697. Pid0Changed = syn:whereis(<<"proc0-changed">>),
  698. Pid1 = syn:whereis(<<"proc1">>),
  699. Pid2 = syn:whereis(<<"proc2">>),
  700. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  701. Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  702. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  703. Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  704. Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
  705. Pid0Changed = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
  706. Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
  707. Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
  708. %% disconnect slave 2 from main (slave 1 can still see slave 2)
  709. syn_test_suite_helper:disconnect_node(SlaveNode2),
  710. timer:sleep(500),
  711. %% retrieve
  712. Pid0 = syn:whereis(<<"proc0">>),
  713. Pid0Changed = syn:whereis(<<"proc0-changed">>),
  714. Pid1 = syn:whereis(<<"proc1">>),
  715. undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
  716. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  717. Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  718. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  719. Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]), %% slave 1 still has slave 2 so 'proc2' is still there
  720. %% disconnect slave 2 from slave 1
  721. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  722. timer:sleep(500),
  723. %% retrieve
  724. Pid0 = syn:whereis(<<"proc0">>),
  725. Pid0Changed = syn:whereis(<<"proc0-changed">>),
  726. Pid1 = syn:whereis(<<"proc1">>),
  727. undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
  728. undefined = syn:whereis(<<"proc2">>, with_meta),
  729. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  730. Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  731. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  732. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  733. %% disconnect slave 1
  734. syn_test_suite_helper:disconnect_node(SlaveNode1),
  735. timer:sleep(500),
  736. %% unregister
  737. ok = syn:unregister(<<"proc0-changed">>),
  738. %% retrieve
  739. Pid0 = syn:whereis(<<"proc0">>),
  740. undefined = syn:whereis(<<"proc0-changed">>),
  741. undefined = syn:whereis(<<"proc1">>),
  742. undefined = syn:whereis(<<"proc2">>),
  743. %% reconnect all
  744. syn_test_suite_helper:connect_node(SlaveNode1),
  745. syn_test_suite_helper:connect_node(SlaveNode2),
  746. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  747. timer:sleep(1500),
  748. %% retrieve
  749. Pid0 = syn:whereis(<<"proc0">>),
  750. undefined = syn:whereis(<<"proc0-changed">>),
  751. Pid1 = syn:whereis(<<"proc1">>),
  752. Pid2 = syn:whereis(<<"proc2">>),
  753. Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
  754. undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
  755. Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
  756. Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
  757. Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
  758. undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
  759. Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
  760. Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]).
  761. three_nodes_start_syn_before_connecting_cluster_with_conflict(Config) ->
  762. ConflictingName = "COMMON",
  763. %% get slaves
  764. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  765. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  766. %% start processes
  767. Pid0 = syn_test_suite_helper:start_process(),
  768. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  769. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  770. %% start delayed
  771. start_syn_delayed_and_register_local_process(ConflictingName, Pid0, 1500),
  772. rpc:cast(SlaveNode1, ?MODULE, start_syn_delayed_and_register_local_process, [ConflictingName, Pid1, 1500]),
  773. rpc:cast(SlaveNode2, ?MODULE, start_syn_delayed_and_register_local_process, [ConflictingName, Pid2, 1500]),
  774. timer:sleep(500),
  775. %% disconnect all
  776. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  777. syn_test_suite_helper:disconnect_node(SlaveNode1),
  778. syn_test_suite_helper:disconnect_node(SlaveNode2),
  779. timer:sleep(1500),
  780. [] = nodes(),
  781. %% reconnect all
  782. syn_test_suite_helper:connect_node(SlaveNode1),
  783. syn_test_suite_helper:connect_node(SlaveNode2),
  784. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  785. timer:sleep(1500),
  786. %% count
  787. 1 = syn:registry_count(),
  788. 1 = rpc:call(SlaveNode1, syn, registry_count, []),
  789. 1 = rpc:call(SlaveNode2, syn, registry_count, []),
  790. %% retrieve
  791. true = lists:member(syn:whereis(ConflictingName), [Pid0, Pid1, Pid2]),
  792. true = lists:member(rpc:call(SlaveNode1, syn, whereis, [ConflictingName]), [Pid0, Pid1, Pid2]),
  793. true = lists:member(rpc:call(SlaveNode2, syn, whereis, [ConflictingName]), [Pid0, Pid1, Pid2]),
  794. %% check metadata
  795. case syn:whereis(ConflictingName, with_meta) of
  796. {Pid0, Meta} ->
  797. CurrentNode = node(),
  798. %% check that other nodes' data corresponds
  799. {Pid0, CurrentNode} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  800. {Pid0, CurrentNode} = rpc:call(SlaveNode2, syn, whereis, [ConflictingName, with_meta]),
  801. %% check that other processes are not alive because syn killed them
  802. true = is_process_alive(Pid0),
  803. false = rpc:call(SlaveNode1, erlang, is_process_alive, [Pid1]),
  804. false = rpc:call(SlaveNode2, erlang, is_process_alive, [Pid2]);
  805. {Pid1, Meta} ->
  806. SlaveNode1 = Meta,
  807. %% check that other nodes' data corresponds
  808. {Pid1, Meta} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  809. {Pid1, Meta} = rpc:call(SlaveNode2, syn, whereis, [ConflictingName, with_meta]),
  810. %% check that other processes are not alive because syn killed them
  811. false = is_process_alive(Pid0),
  812. true = rpc:call(SlaveNode1, erlang, is_process_alive, [Pid1]),
  813. false = rpc:call(SlaveNode2, erlang, is_process_alive, [Pid2]);
  814. {Pid2, Meta} ->
  815. SlaveNode2 = Meta,
  816. %% check that other nodes' data corresponds
  817. {Pid2, Meta} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  818. {Pid2, Meta} = rpc:call(SlaveNode2, syn, whereis, [ConflictingName, with_meta]),
  819. %% check that other processes are not alive because syn killed them
  820. false = is_process_alive(Pid0),
  821. false = rpc:call(SlaveNode1, erlang, is_process_alive, [Pid1]),
  822. true = rpc:call(SlaveNode2, erlang, is_process_alive, [Pid2]);
  823. _ ->
  824. ok = no_process_is_registered_with_conflicting_name
  825. end.
  826. three_nodes_start_syn_before_connecting_cluster_with_custom_conflict_resolution(Config) ->
  827. ConflictingName = "COMMON",
  828. %% get slaves
  829. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  830. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  831. %% start processes
  832. Pid0 = syn_test_suite_helper:start_process(),
  833. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  834. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  835. %% start delayed
  836. start_syn_delayed_with_custom_handler_register_local_process(ConflictingName, Pid0, {node, node()}, 1500),
  837. rpc:cast(
  838. SlaveNode1,
  839. ?MODULE,
  840. start_syn_delayed_with_custom_handler_register_local_process,
  841. [ConflictingName, Pid1, keep_this_one, 1500])
  842. ,
  843. rpc:cast(
  844. SlaveNode2,
  845. ?MODULE,
  846. start_syn_delayed_with_custom_handler_register_local_process,
  847. [ConflictingName, Pid2, {node, SlaveNode2}, 1500]
  848. ),
  849. timer:sleep(500),
  850. %% disconnect all
  851. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  852. syn_test_suite_helper:disconnect_node(SlaveNode1),
  853. syn_test_suite_helper:disconnect_node(SlaveNode2),
  854. timer:sleep(1500),
  855. [] = nodes(),
  856. %% reconnect all
  857. syn_test_suite_helper:connect_node(SlaveNode1),
  858. syn_test_suite_helper:connect_node(SlaveNode2),
  859. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  860. timer:sleep(5000),
  861. %% count
  862. 1 = syn:registry_count(),
  863. 1 = rpc:call(SlaveNode1, syn, registry_count, []),
  864. 1 = rpc:call(SlaveNode2, syn, registry_count, []),
  865. %% retrieve
  866. true = lists:member(syn:whereis(ConflictingName), [Pid0, Pid1, Pid2]),
  867. true = lists:member(rpc:call(SlaveNode1, syn, whereis, [ConflictingName]), [Pid0, Pid1, Pid2]),
  868. true = lists:member(rpc:call(SlaveNode2, syn, whereis, [ConflictingName]), [Pid0, Pid1, Pid2]),
  869. %% check metadata that we kept the correct process on all nodes
  870. {Pid1, keep_this_one} = syn:whereis(ConflictingName, with_meta),
  871. {Pid1, keep_this_one} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  872. {Pid1, keep_this_one} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  873. %% check that other processes are still alive because we didn't kill them
  874. true = is_process_alive(Pid0),
  875. true = rpc:call(SlaveNode1, erlang, is_process_alive, [Pid1]),
  876. true = rpc:call(SlaveNode2, erlang, is_process_alive, [Pid2]).
  877. three_nodes_registration_race_condition_custom_conflict_resolution(Config) ->
  878. ConflictingName = "COMMON",
  879. %% get slaves
  880. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  881. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  882. %% use customer handler
  883. syn_test_suite_helper:use_custom_handler(),
  884. rpc:call(SlaveNode1, syn_test_suite_helper, use_custom_handler, []),
  885. rpc:call(SlaveNode2, syn_test_suite_helper, use_custom_handler, []),
  886. %% start syn on nodes
  887. ok = syn:start(),
  888. ok = rpc:call(SlaveNode1, syn, start, []),
  889. ok = rpc:call(SlaveNode2, syn, start, []),
  890. timer:sleep(500),
  891. %% start processes
  892. Pid0 = syn_test_suite_helper:start_process(),
  893. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  894. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  895. %% inject into syn to simulate concurrent registration
  896. ok = rpc:call(SlaveNode1, syn_registry, add_to_local_table, [ConflictingName, Pid1, keep_this_one, undefined]),
  897. %% register on master node to trigger conflict resolution
  898. ok = syn:register(ConflictingName, Pid0, node()),
  899. timer:sleep(1000),
  900. %% retrieve
  901. true = lists:member(syn:whereis(ConflictingName), [Pid0, Pid1, Pid2]),
  902. true = lists:member(rpc:call(SlaveNode1, syn, whereis, [ConflictingName]), [Pid0, Pid1, Pid2]),
  903. true = lists:member(rpc:call(SlaveNode2, syn, whereis, [ConflictingName]), [Pid0, Pid1, Pid2]),
  904. %% check metadata that we kept the correct process on all nodes
  905. {Pid1, keep_this_one} = syn:whereis(ConflictingName, with_meta),
  906. {Pid1, keep_this_one} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  907. {Pid1, keep_this_one} = rpc:call(SlaveNode1, syn, whereis, [ConflictingName, with_meta]),
  908. %% check that other processes are still alive because we didn't kill them
  909. true = is_process_alive(Pid0),
  910. true = rpc:call(SlaveNode1, erlang, is_process_alive, [Pid1]),
  911. true = rpc:call(SlaveNode2, erlang, is_process_alive, [Pid2]).
  912. three_nodes_anti_entropy(Config) ->
  913. %% get slaves
  914. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  915. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  916. %% use customer handler
  917. syn_test_suite_helper:use_custom_handler(),
  918. rpc:call(SlaveNode1, syn_test_suite_helper, use_custom_handler, []),
  919. rpc:call(SlaveNode2, syn_test_suite_helper, use_custom_handler, []),
  920. %% set anti-entropy with a very low interval (0.25 second)
  921. syn_test_suite_helper:use_anti_entropy(registry, 0.25),
  922. rpc:call(SlaveNode1, syn_test_suite_helper, use_anti_entropy, [registry, 0.25]),
  923. rpc:call(SlaveNode2, syn_test_suite_helper, use_anti_entropy, [registry, 0.25]),
  924. %% start syn on nodes
  925. ok = syn:start(),
  926. ok = rpc:call(SlaveNode1, syn, start, []),
  927. ok = rpc:call(SlaveNode2, syn, start, []),
  928. timer:sleep(100),
  929. %% start processes
  930. Pid0 = syn_test_suite_helper:start_process(),
  931. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  932. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  933. Pid0Conflict = syn_test_suite_helper:start_process(),
  934. Pid1Conflict = syn_test_suite_helper:start_process(SlaveNode1),
  935. Pid2Conflict = syn_test_suite_helper:start_process(SlaveNode2),
  936. timer:sleep(100),
  937. %% inject data to simulate latent conflicts
  938. ok = syn_registry:add_to_local_table("pid0", Pid0, node(), undefined),
  939. ok = rpc:call(SlaveNode1, syn_registry, add_to_local_table, ["pid1", Pid1, SlaveNode1, undefined]),
  940. ok = rpc:call(SlaveNode2, syn_registry, add_to_local_table, ["pid2", Pid2, SlaveNode2, undefined]),
  941. ok = syn_registry:add_to_local_table("conflict", Pid0Conflict, node(), undefined),
  942. ok = rpc:call(SlaveNode1, syn_registry, add_to_local_table, ["conflict", Pid1Conflict, keep_this_one, undefined]),
  943. ok = rpc:call(SlaveNode2, syn_registry, add_to_local_table, ["conflict", Pid2Conflict, SlaveNode2, undefined]),
  944. %% wait to let anti-entropy settle
  945. timer:sleep(5000),
  946. %% check
  947. Node = node(),
  948. {Pid0, Node} = syn:whereis("pid0", with_meta),
  949. {Pid1, SlaveNode1} = syn:whereis("pid1", with_meta),
  950. {Pid2, SlaveNode2} = syn:whereis("pid2", with_meta),
  951. {Pid1Conflict, keep_this_one} = syn:whereis("conflict", with_meta),
  952. {Pid0, Node} = rpc:call(SlaveNode1, syn, whereis, ["pid0", with_meta]),
  953. {Pid1, SlaveNode1} = rpc:call(SlaveNode1, syn, whereis, ["pid1", with_meta]),
  954. {Pid2, SlaveNode2} = rpc:call(SlaveNode1, syn, whereis, ["pid2", with_meta]),
  955. {Pid1Conflict, keep_this_one} = rpc:call(SlaveNode1, syn, whereis, ["conflict", with_meta]),
  956. {Pid0, Node} = rpc:call(SlaveNode2, syn, whereis, ["pid0", with_meta]),
  957. {Pid1, SlaveNode1} = rpc:call(SlaveNode2, syn, whereis, ["pid1", with_meta]),
  958. {Pid2, SlaveNode2} = rpc:call(SlaveNode2, syn, whereis, ["pid2", with_meta]),
  959. {Pid1Conflict, keep_this_one} = rpc:call(SlaveNode2, syn, whereis, ["conflict", with_meta]).
  960. three_nodes_anti_entropy_manual(Config) ->
  961. %% get slaves
  962. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  963. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  964. %% use customer handler
  965. syn_test_suite_helper:use_custom_handler(),
  966. rpc:call(SlaveNode1, syn_test_suite_helper, use_custom_handler, []),
  967. rpc:call(SlaveNode2, syn_test_suite_helper, use_custom_handler, []),
  968. %% start syn on nodes
  969. ok = syn:start(),
  970. ok = rpc:call(SlaveNode1, syn, start, []),
  971. ok = rpc:call(SlaveNode2, syn, start, []),
  972. timer:sleep(100),
  973. %% start processes
  974. Pid0 = syn_test_suite_helper:start_process(),
  975. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  976. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  977. Pid0Conflict = syn_test_suite_helper:start_process(),
  978. Pid1Conflict = syn_test_suite_helper:start_process(SlaveNode1),
  979. Pid2Conflict = syn_test_suite_helper:start_process(SlaveNode2),
  980. timer:sleep(100),
  981. %% inject data to simulate latent conflicts
  982. ok = syn_registry:add_to_local_table("pid0", Pid0, node(), undefined),
  983. ok = rpc:call(SlaveNode1, syn_registry, add_to_local_table, ["pid1", Pid1, SlaveNode1, undefined]),
  984. ok = rpc:call(SlaveNode2, syn_registry, add_to_local_table, ["pid2", Pid2, SlaveNode2, undefined]),
  985. ok = syn_registry:add_to_local_table("conflict", Pid0Conflict, node(), undefined),
  986. ok = rpc:call(SlaveNode1, syn_registry, add_to_local_table, ["conflict", Pid1Conflict, keep_this_one, undefined]),
  987. ok = rpc:call(SlaveNode2, syn_registry, add_to_local_table, ["conflict", Pid2Conflict, SlaveNode2, undefined]),
  988. %% call anti entropy
  989. {error, not_remote_node} = syn:sync_from_node(registry, node()),
  990. ok = syn:sync_from_node(registry, SlaveNode1),
  991. ok = syn:sync_from_node(registry, SlaveNode2),
  992. {error, not_remote_node} = rpc:call(SlaveNode1, syn, sync_from_node, [registry, SlaveNode1]),
  993. ok = rpc:call(SlaveNode1, syn, sync_from_node, [registry, node()]),
  994. ok = rpc:call(SlaveNode1, syn, sync_from_node, [registry, SlaveNode2]),
  995. {error, not_remote_node} = rpc:call(SlaveNode2, syn, sync_from_node, [registry, SlaveNode2]),
  996. ok = rpc:call(SlaveNode2, syn, sync_from_node, [registry, node()]),
  997. ok = rpc:call(SlaveNode2, syn, sync_from_node, [registry, SlaveNode1]),
  998. timer:sleep(500),
  999. %% check
  1000. Node = node(),
  1001. {Pid0, Node} = syn:whereis("pid0", with_meta),
  1002. {Pid1, SlaveNode1} = syn:whereis("pid1", with_meta),
  1003. {Pid2, SlaveNode2} = syn:whereis("pid2", with_meta),
  1004. {Pid1Conflict, keep_this_one} = syn:whereis("conflict", with_meta),
  1005. {Pid0, Node} = rpc:call(SlaveNode1, syn, whereis, ["pid0", with_meta]),
  1006. {Pid1, SlaveNode1} = rpc:call(SlaveNode1, syn, whereis, ["pid1", with_meta]),
  1007. {Pid2, SlaveNode2} = rpc:call(SlaveNode1, syn, whereis, ["pid2", with_meta]),
  1008. {Pid1Conflict, keep_this_one} = rpc:call(SlaveNode1, syn, whereis, ["conflict", with_meta]),
  1009. {Pid0, Node} = rpc:call(SlaveNode2, syn, whereis, ["pid0", with_meta]),
  1010. {Pid1, SlaveNode1} = rpc:call(SlaveNode2, syn, whereis, ["pid1", with_meta]),
  1011. {Pid2, SlaveNode2} = rpc:call(SlaveNode2, syn, whereis, ["pid2", with_meta]),
  1012. {Pid1Conflict, keep_this_one} = rpc:call(SlaveNode2, syn, whereis, ["conflict", with_meta]).
  1013. %% ===================================================================
  1014. %% Internal
  1015. %% ===================================================================
  1016. start_syn_delayed_and_register_local_process(Name, Pid, Ms) ->
  1017. spawn(fun() ->
  1018. lists:foreach(fun(Node) ->
  1019. syn_test_suite_helper:disconnect_node(Node)
  1020. end, nodes()),
  1021. timer:sleep(Ms),
  1022. [] = nodes(),
  1023. %%
  1024. syn:start(),
  1025. ok = syn:register(Name, Pid, node())
  1026. end).
  1027. start_syn_delayed_with_custom_handler_register_local_process(Name, Pid, Meta, Ms) ->
  1028. spawn(fun() ->
  1029. lists:foreach(fun(Node) ->
  1030. syn_test_suite_helper:disconnect_node(Node)
  1031. end, nodes()),
  1032. timer:sleep(Ms),
  1033. [] = nodes(),
  1034. %% use customer handler
  1035. syn_test_suite_helper:use_custom_handler(),
  1036. %%
  1037. syn:start(),
  1038. ok = syn:register(Name, Pid, Meta)
  1039. end).