syn_groups_SUITE.erl 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  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_groups_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_join_and_monitor/1,
  35. single_node_join_and_leave/1,
  36. single_node_join_errors/1,
  37. single_node_groups_count/1,
  38. single_node_group_names/1,
  39. single_node_publish/1,
  40. single_node_multicall/1,
  41. single_node_multicall_with_custom_timeout/1,
  42. single_node_callback_on_process_exit/1,
  43. single_node_monitor_after_group_crash/1
  44. ]).
  45. -export([
  46. two_nodes_join_monitor_and_unregister/1,
  47. two_nodes_local_members/1,
  48. two_nodes_groups_count/1,
  49. two_nodes_group_names/1,
  50. two_nodes_publish/1,
  51. two_nodes_local_publish/1,
  52. two_nodes_multicall/1,
  53. two_nodes_groups_full_cluster_sync_on_boot_node_added_later/1,
  54. two_nodes_groups_full_cluster_sync_on_boot_syn_started_later/1,
  55. three_nodes_anti_entropy/1,
  56. three_nodes_anti_entropy_manual/1
  57. ]).
  58. -export([
  59. three_nodes_partial_netsplit_consistency/1,
  60. three_nodes_full_netsplit_consistency/1
  61. ]).
  62. %% include
  63. -include_lib("common_test/include/ct.hrl").
  64. %% ===================================================================
  65. %% Callbacks
  66. %% ===================================================================
  67. %% -------------------------------------------------------------------
  68. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  69. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  70. %% GroupName = atom()
  71. %% TestCase = atom()
  72. %% Reason = any()
  73. %% -------------------------------------------------------------------
  74. all() ->
  75. [
  76. {group, single_node_groups},
  77. {group, two_nodes_groups},
  78. {group, three_nodes_groups}
  79. ].
  80. %% -------------------------------------------------------------------
  81. %% Function: groups() -> [Group]
  82. %% Group = {GroupName,Properties,GroupsAndTestCases}
  83. %% GroupName = atom()
  84. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  85. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  86. %% TestCase = atom()
  87. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  88. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  89. %% repeat_until_any_ok | repeat_until_any_fail
  90. %% N = integer() | forever
  91. %% -------------------------------------------------------------------
  92. groups() ->
  93. [
  94. {single_node_groups, [shuffle], [
  95. single_node_join_and_monitor,
  96. single_node_join_and_leave,
  97. single_node_join_errors,
  98. single_node_groups_count,
  99. single_node_group_names,
  100. single_node_publish,
  101. single_node_multicall,
  102. single_node_multicall_with_custom_timeout,
  103. single_node_callback_on_process_exit,
  104. single_node_monitor_after_group_crash
  105. ]},
  106. {two_nodes_groups, [shuffle], [
  107. two_nodes_join_monitor_and_unregister,
  108. two_nodes_local_members,
  109. two_nodes_groups_count,
  110. two_nodes_group_names,
  111. two_nodes_publish,
  112. two_nodes_local_publish,
  113. two_nodes_multicall,
  114. two_nodes_groups_full_cluster_sync_on_boot_node_added_later,
  115. two_nodes_groups_full_cluster_sync_on_boot_syn_started_later
  116. ]},
  117. {three_nodes_groups, [shuffle], [
  118. three_nodes_partial_netsplit_consistency,
  119. three_nodes_full_netsplit_consistency,
  120. three_nodes_anti_entropy,
  121. three_nodes_anti_entropy_manual
  122. ]}
  123. ].
  124. %% -------------------------------------------------------------------
  125. %% Function: init_per_suite(Config0) ->
  126. %% Config1 | {skip,Reason} |
  127. %% {skip_and_save,Reason,Config1}
  128. %% Config0 = Config1 = [tuple()]
  129. %% Reason = any()
  130. %% -------------------------------------------------------------------
  131. init_per_suite(Config) ->
  132. Config.
  133. %% -------------------------------------------------------------------
  134. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  135. %% Config0 = Config1 = [tuple()]
  136. %% -------------------------------------------------------------------
  137. end_per_suite(_Config) ->
  138. ok.
  139. %% -------------------------------------------------------------------
  140. %% Function: init_per_group(GroupName, Config0) ->
  141. %% Config1 | {skip,Reason} |
  142. %% {skip_and_save,Reason,Config1}
  143. %% GroupName = atom()
  144. %% Config0 = Config1 = [tuple()]
  145. %% Reason = any()
  146. %% -------------------------------------------------------------------
  147. init_per_group(two_nodes_groups, Config) ->
  148. %% start slave
  149. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  150. %% config
  151. [{slave_node, SlaveNode} | Config];
  152. init_per_group(three_nodes_groups, Config) ->
  153. %% start slave
  154. {ok, SlaveNode1} = syn_test_suite_helper:start_slave(syn_slave_1),
  155. {ok, SlaveNode2} = syn_test_suite_helper:start_slave(syn_slave_2),
  156. %% config
  157. [{slave_node_1, SlaveNode1}, {slave_node_2, SlaveNode2} | Config];
  158. init_per_group(_GroupName, Config) ->
  159. Config.
  160. %% -------------------------------------------------------------------
  161. %% Function: end_per_group(GroupName, Config0) ->
  162. %% void() | {save_config,Config1}
  163. %% GroupName = atom()
  164. %% Config0 = Config1 = [tuple()]
  165. %% -------------------------------------------------------------------
  166. end_per_group(two_nodes_groups, Config) ->
  167. SlaveNode = proplists:get_value(slave_node, Config),
  168. syn_test_suite_helper:connect_node(SlaveNode),
  169. syn_test_suite_helper:clean_after_test(),
  170. syn_test_suite_helper:stop_slave(syn_slave),
  171. timer:sleep(1000);
  172. end_per_group(three_nodes_groups, Config) ->
  173. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  174. syn_test_suite_helper:connect_node(SlaveNode1),
  175. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  176. syn_test_suite_helper:connect_node(SlaveNode2),
  177. syn_test_suite_helper:clean_after_test(),
  178. syn_test_suite_helper:stop_slave(syn_slave_1),
  179. syn_test_suite_helper:stop_slave(syn_slave_2),
  180. timer:sleep(1000);
  181. end_per_group(_GroupName, _Config) ->
  182. syn_test_suite_helper:clean_after_test().
  183. %% -------------------------------------------------------------------
  184. %% Function: init_per_testcase(TestCase, Config0) ->
  185. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  186. %% TestCase = atom()
  187. %% Config0 = Config1 = [tuple()]
  188. %% Reason = any()
  189. %% -------------------------------------------------------------------
  190. init_per_testcase(TestCase, Config) ->
  191. ct:pal("Starting test: ~p", [TestCase]),
  192. Config.
  193. %% -------------------------------------------------------------------
  194. %% Function: end_per_testcase(TestCase, Config0) ->
  195. %% void() | {save_config,Config1} | {fail,Reason}
  196. %% TestCase = atom()
  197. %% Config0 = Config1 = [tuple()]
  198. %% Reason = any()
  199. %% -------------------------------------------------------------------
  200. end_per_testcase(_, _Config) ->
  201. syn_test_suite_helper:clean_after_test().
  202. %% ===================================================================
  203. %% Tests
  204. %% ===================================================================
  205. single_node_join_and_monitor(_Config) ->
  206. GroupName = "my group",
  207. %% start
  208. ok = syn:start(),
  209. %% start processes
  210. Pid = syn_test_suite_helper:start_process(),
  211. PidWithMeta = syn_test_suite_helper:start_process(),
  212. PidOther = syn_test_suite_helper:start_process(),
  213. %% retrieve
  214. [] = syn:get_members(GroupName),
  215. [] = syn:get_members(GroupName, with_meta),
  216. false = syn:member(Pid, GroupName),
  217. false = syn:member(PidWithMeta, GroupName),
  218. false = syn:member(PidOther, GroupName),
  219. %% join
  220. ok = syn:join(GroupName, Pid),
  221. ok = syn:join(GroupName, PidWithMeta, {with, meta}),
  222. ok = syn:join("other-group", PidOther),
  223. %% retrieve
  224. true = syn:member(Pid, GroupName),
  225. true = syn:member(PidWithMeta, GroupName),
  226. false = syn:member(PidOther, GroupName),
  227. true = lists:sort([Pid, PidWithMeta]) =:= lists:sort(syn:get_members(GroupName)),
  228. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with, meta}}])
  229. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  230. %% re-join
  231. ok = syn:join(GroupName, PidWithMeta, {with2, meta2}),
  232. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with2, meta2}}])
  233. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  234. %% kill process
  235. syn_test_suite_helper:kill_process(Pid),
  236. syn_test_suite_helper:kill_process(PidWithMeta),
  237. syn_test_suite_helper:kill_process(PidOther),
  238. timer:sleep(100),
  239. %% retrieve
  240. [] = syn:get_members(GroupName),
  241. [] = syn:get_members(GroupName, with_meta),
  242. false = syn:member(Pid, GroupName),
  243. false = syn:member(PidWithMeta, GroupName).
  244. single_node_join_and_leave(_Config) ->
  245. GroupName = "my group",
  246. %% start
  247. ok = syn:start(),
  248. %% start processes
  249. Pid = syn_test_suite_helper:start_process(),
  250. PidWithMeta = syn_test_suite_helper:start_process(),
  251. %% retrieve
  252. [] = syn:get_members(GroupName),
  253. [] = syn:get_members(GroupName, with_meta),
  254. false = syn:member(Pid, GroupName),
  255. false = syn:member(PidWithMeta, GroupName),
  256. %% join
  257. ok = syn:join(GroupName, Pid),
  258. ok = syn:join(GroupName, PidWithMeta, {with, meta}),
  259. %% retrieve
  260. true = syn:member(Pid, GroupName),
  261. true = syn:member(PidWithMeta, GroupName),
  262. true = lists:sort([Pid, PidWithMeta]) =:= lists:sort(syn:get_members(GroupName)),
  263. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with, meta}}])
  264. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  265. %% leave
  266. ok = syn:leave(GroupName, Pid),
  267. ok = syn:leave(GroupName, PidWithMeta),
  268. timer:sleep(100),
  269. %% retrieve
  270. [] = syn:get_members(GroupName),
  271. [] = syn:get_members(GroupName, with_meta),
  272. false = syn:member(Pid, GroupName),
  273. false = syn:member(PidWithMeta, GroupName).
  274. single_node_join_errors(_Config) ->
  275. GroupName = "my group",
  276. %% start
  277. ok = syn:start(),
  278. %% start processes
  279. Pid = syn_test_suite_helper:start_process(),
  280. Pid2 = syn_test_suite_helper:start_process(),
  281. %% join
  282. ok = syn:join(GroupName, Pid),
  283. ok = syn:join(GroupName, Pid2),
  284. true = syn:member(Pid, GroupName),
  285. true = syn:member(Pid2, GroupName),
  286. %% leave
  287. ok = syn:leave(GroupName, Pid),
  288. {error, not_in_group} = syn:leave(GroupName, Pid),
  289. %% kill
  290. syn_test_suite_helper:kill_process(Pid2),
  291. timer:sleep(200),
  292. {error, not_in_group} = syn:leave(GroupName, Pid2),
  293. {error, not_alive} = syn:join(GroupName, Pid2).
  294. single_node_groups_count(_Config) ->
  295. %% start
  296. ok = syn:start(),
  297. %% start processes
  298. Pid = syn_test_suite_helper:start_process(),
  299. Pid2 = syn_test_suite_helper:start_process(),
  300. Pid3 = syn_test_suite_helper:start_process(),
  301. %% join
  302. ok = syn:join({"group-1"}, Pid),
  303. ok = syn:join({"group-1"}, Pid2),
  304. ok = syn:join({"group-1"}, Pid3),
  305. ok = syn:join({"group-2"}, Pid2),
  306. %% count
  307. 2 = syn:groups_count(),
  308. 2 = syn:groups_count(node()),
  309. %% kill & unregister
  310. ok = syn:leave({"group-1"}, Pid),
  311. syn_test_suite_helper:kill_process(Pid2),
  312. syn_test_suite_helper:kill_process(Pid3),
  313. timer:sleep(100),
  314. %% count
  315. 0 = syn:groups_count(),
  316. 0 = syn:groups_count(node()).
  317. single_node_group_names(_Config) ->
  318. %% start
  319. ok = syn:start(),
  320. %% start processes
  321. Pid = syn_test_suite_helper:start_process(),
  322. Pid2 = syn_test_suite_helper:start_process(),
  323. Pid3 = syn_test_suite_helper:start_process(),
  324. %% join
  325. ok = syn:join({"group-1"}, Pid),
  326. ok = syn:join({"group-1"}, Pid2),
  327. ok = syn:join({"group-1"}, Pid3),
  328. ok = syn:join({"group-2"}, Pid2),
  329. %% names
  330. GroupNames = syn:get_group_names(),
  331. 2 = length(GroupNames),
  332. true = lists:member({"group-1"}, GroupNames),
  333. true = lists:member({"group-2"}, GroupNames),
  334. %% kill & unregister
  335. ok = syn:leave({"group-1"}, Pid),
  336. syn_test_suite_helper:kill_process(Pid2),
  337. syn_test_suite_helper:kill_process(Pid3),
  338. timer:sleep(100),
  339. %% count
  340. [] = syn:get_group_names().
  341. single_node_publish(_Config) ->
  342. GroupName = "my group",
  343. Message = {test, message},
  344. %% start
  345. ok = syn:start(),
  346. %% start processes
  347. ResultPid = self(),
  348. F = fun() ->
  349. receive
  350. Message -> ResultPid ! {received, self(), Message}
  351. end
  352. end,
  353. Pid = syn_test_suite_helper:start_process(F),
  354. Pid2 = syn_test_suite_helper:start_process(F),
  355. _OtherPid = syn_test_suite_helper:start_process(F),
  356. %% join
  357. ok = syn:join(GroupName, Pid),
  358. ok = syn:join(GroupName, Pid2),
  359. true = syn:member(Pid, GroupName),
  360. true = syn:member(Pid2, GroupName),
  361. %% send
  362. {ok, 2} = syn:publish(GroupName, Message),
  363. %% check
  364. receive
  365. {received, Pid, Message} -> ok
  366. after 2000 ->
  367. ok = published_message_was_not_received_by_pid_1
  368. end,
  369. receive
  370. {received, Pid2, Message} -> ok
  371. after 2000 ->
  372. ok = published_message_was_not_received_by_pid_2
  373. end.
  374. single_node_multicall(_Config) ->
  375. GroupName = <<"my group">>,
  376. %% start
  377. ok = syn:start(),
  378. %% start processes
  379. F = fun() ->
  380. receive
  381. {syn_multi_call, RequestorPid, get_pid_name} ->
  382. syn:multi_call_reply(RequestorPid, {pong, self()})
  383. end
  384. end,
  385. Pid1 = syn_test_suite_helper:start_process(F),
  386. Pid2 = syn_test_suite_helper:start_process(F),
  387. PidUnresponsive = syn_test_suite_helper:start_process(),
  388. %% register
  389. ok = syn:join(GroupName, Pid1),
  390. ok = syn:join(GroupName, Pid2),
  391. ok = syn:join(GroupName, PidUnresponsive),
  392. %% call
  393. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name),
  394. %% check responses
  395. true = lists:sort([
  396. {Pid1, {pong, Pid1}},
  397. {Pid2, {pong, Pid2}}
  398. ]) =:= lists:sort(Replies),
  399. [PidUnresponsive] = BadPids.
  400. single_node_multicall_with_custom_timeout(_Config) ->
  401. GroupName = <<"my group">>,
  402. %% start
  403. ok = syn:start(),
  404. %% start processes
  405. F1 = fun() ->
  406. receive
  407. {syn_multi_call, RequestorPid, get_pid_name} ->
  408. syn:multi_call_reply(RequestorPid, {pong, self()})
  409. end
  410. end,
  411. Pid1 = syn_test_suite_helper:start_process(F1),
  412. F2 = fun() ->
  413. receive
  414. {syn_multi_call, RequestorPid, get_pid_name} ->
  415. timer:sleep(5000),
  416. syn:multi_call_reply(RequestorPid, {pong, self()})
  417. end
  418. end,
  419. PidTakesLong = syn_test_suite_helper:start_process(F2),
  420. PidUnresponsive = syn_test_suite_helper:start_process(),
  421. %% register
  422. ok = syn:join(GroupName, Pid1),
  423. ok = syn:join(GroupName, PidTakesLong),
  424. ok = syn:join(GroupName, PidUnresponsive),
  425. %% call
  426. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name, 2000),
  427. %% check responses
  428. [{Pid1, {pong, Pid1}}] = Replies,
  429. true = lists:sort([PidTakesLong, PidUnresponsive]) =:= lists:sort(BadPids).
  430. single_node_callback_on_process_exit(_Config) ->
  431. %% use custom handler
  432. syn_test_suite_helper:use_custom_handler(),
  433. %% start
  434. ok = syn:start(),
  435. %% start processes
  436. Pid = syn_test_suite_helper:start_process(),
  437. Pid2 = syn_test_suite_helper:start_process(),
  438. %% join
  439. TestPid = self(),
  440. ok = syn:join(group_1, Pid, {pid_group_1, TestPid}),
  441. ok = syn:join(group_2, Pid, {pid_group_2, TestPid}),
  442. ok = syn:join(group_1, Pid2, {pid2, TestPid}),
  443. %% kill 1
  444. syn_test_suite_helper:kill_process(Pid),
  445. receive
  446. {received_event_on, pid_group_1} ->
  447. ok;
  448. {received_event_on, pid2} ->
  449. ok = callback_on_process_exit_was_received_by_pid2
  450. after 1000 ->
  451. ok = callback_on_process_exit_was_not_received_by_pid
  452. end,
  453. receive
  454. {received_event_on, pid_group_2} ->
  455. ok;
  456. {received_event_on, pid2} ->
  457. ok = callback_on_process_exit_was_received_by_pid2
  458. after 1000 ->
  459. ok = callback_on_process_exit_was_not_received_by_pid
  460. end,
  461. %% unregister & kill 2
  462. ok = syn:leave(group_1, Pid2),
  463. syn_test_suite_helper:kill_process(Pid2),
  464. receive
  465. {received_event_on, pid2} ->
  466. ok = callback_on_process_exit_was_received_by_pid2
  467. after 1000 ->
  468. ok
  469. end.
  470. single_node_monitor_after_group_crash(_Config) ->
  471. GroupName = "my group",
  472. %% start
  473. ok = syn:start(),
  474. %% start processes
  475. Pid = syn_test_suite_helper:start_process(),
  476. %% join
  477. ok = syn:join(GroupName, Pid),
  478. %% kill groups
  479. exit(whereis(syn_groups), kill),
  480. timer:sleep(200),
  481. %% retrieve
  482. true = syn:member(Pid, GroupName),
  483. [Pid] = syn:get_members(GroupName),
  484. %% kill process
  485. syn_test_suite_helper:kill_process(Pid),
  486. timer:sleep(200),
  487. %% retrieve
  488. false = syn:member(Pid, GroupName),
  489. [] = syn:get_members(GroupName).
  490. two_nodes_join_monitor_and_unregister(Config) ->
  491. GroupName = "my group",
  492. %% get slave
  493. SlaveNode = proplists:get_value(slave_node, Config),
  494. %% start
  495. ok = syn:start(),
  496. ok = rpc:call(SlaveNode, syn, start, []),
  497. timer:sleep(100),
  498. %% start processes
  499. LocalPid = syn_test_suite_helper:start_process(),
  500. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  501. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  502. OtherPid = syn_test_suite_helper:start_process(),
  503. %% retrieve
  504. [] = syn:get_members("group-1"),
  505. [] = syn:get_members(GroupName),
  506. [] = syn:get_members(GroupName, with_meta),
  507. false = syn:member(LocalPid, GroupName),
  508. false = syn:member(RemotePid, GroupName),
  509. false = syn:member(RemotePidJoinRemote, GroupName),
  510. false = syn:member(OtherPid, GroupName),
  511. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  512. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  513. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  514. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  515. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  516. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  517. %% join
  518. ok = syn:join(GroupName, LocalPid),
  519. ok = syn:join(GroupName, RemotePid, {with_meta}),
  520. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  521. ok = syn:join("other-group", OtherPid),
  522. timer:sleep(200),
  523. %% retrieve local
  524. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote]) =:= lists:sort(syn:get_members(GroupName)),
  525. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  526. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  527. true = syn:member(LocalPid, GroupName),
  528. true = syn:member(RemotePid, GroupName),
  529. true = syn:member(RemotePidJoinRemote, GroupName),
  530. false = syn:member(OtherPid, GroupName),
  531. %% retrieve remote
  532. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote])
  533. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName])),
  534. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  535. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta])),
  536. true = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  537. true = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  538. true = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  539. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  540. %% leave & kill
  541. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  542. ok = syn:leave(GroupName, RemotePid),
  543. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  544. syn_test_suite_helper:kill_process(OtherPid),
  545. timer:sleep(200),
  546. %% retrieve
  547. [] = syn:get_members("group-1"),
  548. [] = syn:get_members(GroupName),
  549. [] = syn:get_members(GroupName, with_meta),
  550. false = syn:member(LocalPid, GroupName),
  551. false = syn:member(RemotePid, GroupName),
  552. false = syn:member(RemotePidJoinRemote, GroupName),
  553. false = syn:member(OtherPid, GroupName),
  554. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  555. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  556. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  557. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  558. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  559. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]).
  560. two_nodes_local_members(Config) ->
  561. GroupName = "my group",
  562. %% get slave
  563. SlaveNode = proplists:get_value(slave_node, Config),
  564. %% start
  565. ok = syn:start(),
  566. ok = rpc:call(SlaveNode, syn, start, []),
  567. timer:sleep(100),
  568. %% start processes
  569. LocalPid = syn_test_suite_helper:start_process(),
  570. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  571. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  572. OtherPid = syn_test_suite_helper:start_process(),
  573. %% local members
  574. [] = syn:get_local_members(GroupName),
  575. [] = syn:get_local_members(GroupName, with_meta),
  576. false = syn:local_member(LocalPid, GroupName),
  577. false = syn:local_member(RemotePid, GroupName),
  578. false = syn:local_member(RemotePidJoinRemote, GroupName),
  579. false = syn:local_member(OtherPid, GroupName),
  580. %% remote members
  581. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  582. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]),
  583. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  584. false = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  585. false = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  586. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  587. %% join
  588. ok = syn:join(GroupName, LocalPid),
  589. ok = syn:join(GroupName, RemotePid, {meta, 2}),
  590. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  591. ok = syn:join({"other-group"}, OtherPid),
  592. timer:sleep(200),
  593. %% local members
  594. [LocalPid] = syn:get_local_members(GroupName),
  595. [{LocalPid, undefined}] = syn:get_local_members(GroupName, with_meta),
  596. [OtherPid] = syn:get_local_members({"other-group"}),
  597. true = syn:local_member(LocalPid, GroupName),
  598. false = syn:local_member(RemotePid, GroupName),
  599. false = syn:local_member(RemotePidJoinRemote, GroupName),
  600. false = syn:local_member(OtherPid, GroupName),
  601. true = syn:local_member(OtherPid, {"other-group"}),
  602. %% remote members
  603. true = lists:sort([RemotePid, RemotePidJoinRemote])
  604. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName])),
  605. true = lists:sort([{RemotePid, {meta, 2}}, {RemotePidJoinRemote, undefined}])
  606. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta])),
  607. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  608. true = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  609. true = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  610. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  611. %% leave & kill
  612. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  613. ok = syn:leave(GroupName, RemotePid),
  614. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  615. syn_test_suite_helper:kill_process(OtherPid),
  616. timer:sleep(200),
  617. %% local members
  618. [] = syn:get_local_members(GroupName),
  619. [] = syn:get_local_members(GroupName, with_meta),
  620. %% remote members
  621. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  622. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]).
  623. two_nodes_groups_count(Config) ->
  624. %% get slave
  625. SlaveNode = proplists:get_value(slave_node, Config),
  626. %% start
  627. ok = syn:start(),
  628. ok = rpc:call(SlaveNode, syn, start, []),
  629. timer:sleep(100),
  630. %% start processes
  631. LocalPid = syn_test_suite_helper:start_process(),
  632. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  633. RemotePidRegRemote = syn_test_suite_helper:start_process(SlaveNode),
  634. _PidUnjoined = syn_test_suite_helper:start_process(),
  635. %% join
  636. ok = syn:join(<<"local group">>, LocalPid),
  637. ok = syn:join(<<"remote group">>, RemotePid),
  638. ok = rpc:call(SlaveNode, syn, join, [<<"remote group join_remote">>, RemotePidRegRemote]),
  639. timer:sleep(500),
  640. %% count
  641. 3 = syn:groups_count(),
  642. 1 = syn:groups_count(node()),
  643. 2 = syn:groups_count(SlaveNode),
  644. %% kill & unregister processes
  645. syn_test_suite_helper:kill_process(LocalPid),
  646. ok = syn:leave(<<"remote group">>, RemotePid),
  647. syn_test_suite_helper:kill_process(RemotePidRegRemote),
  648. timer:sleep(100),
  649. %% count
  650. 0 = syn:groups_count(),
  651. 0 = syn:groups_count(node()),
  652. 0 = syn:groups_count(SlaveNode).
  653. two_nodes_group_names(Config) ->
  654. %% get slave
  655. SlaveNode = proplists:get_value(slave_node, Config),
  656. %% start
  657. ok = syn:start(),
  658. ok = rpc:call(SlaveNode, syn, start, []),
  659. timer:sleep(100),
  660. %% start processes
  661. LocalPid = syn_test_suite_helper:start_process(),
  662. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  663. RemotePidRegRemote = syn_test_suite_helper:start_process(SlaveNode),
  664. _PidUnjoined = syn_test_suite_helper:start_process(),
  665. %% join
  666. ok = syn:join(<<"local group">>, LocalPid),
  667. ok = syn:join(<<"remote group">>, RemotePid),
  668. ok = rpc:call(SlaveNode, syn, join, [<<"remote group join_remote">>, RemotePidRegRemote]),
  669. timer:sleep(500),
  670. %% names
  671. GroupNames = syn:get_group_names(),
  672. 3 = length(GroupNames),
  673. true = lists:member(<<"local group">>, GroupNames),
  674. true = lists:member(<<"remote group">>, GroupNames),
  675. true = lists:member(<<"remote group join_remote">>, GroupNames),
  676. %% kill & unregister processes
  677. syn_test_suite_helper:kill_process(LocalPid),
  678. ok = syn:leave(<<"remote group">>, RemotePid),
  679. syn_test_suite_helper:kill_process(RemotePidRegRemote),
  680. timer:sleep(100),
  681. %% names
  682. [] = syn:get_group_names().
  683. two_nodes_publish(Config) ->
  684. GroupName = "my group",
  685. Message = {test, message},
  686. %% get slave
  687. SlaveNode = proplists:get_value(slave_node, Config),
  688. %% start
  689. ok = syn:start(),
  690. ok = rpc:call(SlaveNode, syn, start, []),
  691. timer:sleep(100),
  692. %% start processes
  693. ResultPid = self(),
  694. F = fun() ->
  695. receive
  696. Message -> ResultPid ! {received, self(), Message}
  697. end
  698. end,
  699. LocalPid = syn_test_suite_helper:start_process(F),
  700. LocalPid2 = syn_test_suite_helper:start_process(F),
  701. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  702. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  703. OtherPid = syn_test_suite_helper:start_process(F),
  704. %% join
  705. ok = syn:join(GroupName, LocalPid),
  706. ok = syn:join(GroupName, LocalPid2),
  707. ok = syn:join(GroupName, RemotePid),
  708. ok = syn:join(GroupName, RemotePid2),
  709. timer:sleep(200),
  710. %% send
  711. {ok, 4} = syn:publish(GroupName, Message),
  712. %% check
  713. receive
  714. {received, LocalPid, Message} -> ok
  715. after 2000 ->
  716. ok = published_message_was_not_received_by_local_pid
  717. end,
  718. receive
  719. {received, LocalPid2, Message} -> ok
  720. after 2000 ->
  721. ok = published_message_was_not_received_by_local_pid_2
  722. end,
  723. receive
  724. {received, RemotePid, Message} -> ok
  725. after 2000 ->
  726. ok = published_message_was_not_received_by_remote_pid
  727. end,
  728. receive
  729. {received, RemotePid2, Message} -> ok
  730. after 2000 ->
  731. ok = published_message_was_not_received_by_remote_pid_2
  732. end,
  733. receive
  734. {received, OtherPid, Message} ->
  735. ok = published_message_was_received_by_other_pid
  736. after 250 ->
  737. ok
  738. end.
  739. two_nodes_local_publish(Config) ->
  740. GroupName = "my group",
  741. Message = {test, message},
  742. %% get slave
  743. SlaveNode = proplists:get_value(slave_node, Config),
  744. %% start
  745. ok = syn:start(),
  746. ok = rpc:call(SlaveNode, syn, start, []),
  747. timer:sleep(100),
  748. %% start processes
  749. ResultPid = self(),
  750. F = fun() ->
  751. receive
  752. Message -> ResultPid ! {received, self(), Message}
  753. end
  754. end,
  755. LocalPid = syn_test_suite_helper:start_process(F),
  756. LocalPid2 = syn_test_suite_helper:start_process(F),
  757. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  758. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  759. OtherPid = syn_test_suite_helper:start_process(F),
  760. %% join
  761. ok = syn:join(GroupName, LocalPid),
  762. ok = syn:join(GroupName, LocalPid2),
  763. ok = syn:join(GroupName, RemotePid),
  764. ok = syn:join(GroupName, RemotePid2),
  765. timer:sleep(200),
  766. %% send
  767. {ok, 2} = syn:publish_to_local(GroupName, Message),
  768. %% check
  769. receive
  770. {received, LocalPid, Message} -> ok
  771. after 2000 ->
  772. ok = published_message_was_not_received_by_local_pid
  773. end,
  774. receive
  775. {received, LocalPid2, Message} -> ok
  776. after 2000 ->
  777. ok = published_message_was_not_received_by_local_pid_2
  778. end,
  779. receive
  780. {received, RemotePid, Message} ->
  781. ok = published_message_was_received_by_remote_pid
  782. after 250 ->
  783. ok
  784. end,
  785. receive
  786. {received, RemotePid, Message} ->
  787. ok = published_message_was_received_by_remote_pid_2
  788. after 250 ->
  789. ok
  790. end,
  791. receive
  792. {received, OtherPid, Message} ->
  793. ok = published_message_was_received_by_other_pid
  794. after 250 ->
  795. ok
  796. end.
  797. two_nodes_multicall(Config) ->
  798. GroupName = <<"my group">>,
  799. %% get slave
  800. SlaveNode = proplists:get_value(slave_node, Config),
  801. %% start
  802. ok = syn:start(),
  803. ok = rpc:call(SlaveNode, syn, start, []),
  804. timer:sleep(100),
  805. %% start processes
  806. F = fun() ->
  807. receive
  808. {syn_multi_call, RequestorPid, get_pid_name} ->
  809. syn:multi_call_reply(RequestorPid, {pong, self()})
  810. end
  811. end,
  812. Pid1 = syn_test_suite_helper:start_process(F),
  813. Pid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  814. PidUnresponsive = syn_test_suite_helper:start_process(),
  815. %% register
  816. ok = syn:join(GroupName, Pid1),
  817. ok = syn:join(GroupName, Pid2),
  818. ok = syn:join(GroupName, PidUnresponsive),
  819. timer:sleep(500),
  820. %% call
  821. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name),
  822. %% check responses
  823. true = lists:sort([
  824. {Pid1, {pong, Pid1}},
  825. {Pid2, {pong, Pid2}}
  826. ]) =:= lists:sort(Replies),
  827. [PidUnresponsive] = BadPids.
  828. two_nodes_groups_full_cluster_sync_on_boot_node_added_later(_Config) ->
  829. %% stop slave
  830. syn_test_suite_helper:stop_slave(syn_slave),
  831. %% start syn on local node
  832. ok = syn:start(),
  833. %% start process
  834. Pid = syn_test_suite_helper:start_process(),
  835. %% register
  836. ok = syn:join(<<"group">>, Pid),
  837. %% start remote node and syn
  838. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  839. ok = rpc:call(SlaveNode, syn, start, []),
  840. timer:sleep(1000),
  841. %% check
  842. [Pid] = syn:get_members(<<"group">>),
  843. [Pid] = rpc:call(SlaveNode, syn, get_members, [<<"group">>]).
  844. two_nodes_groups_full_cluster_sync_on_boot_syn_started_later(Config) ->
  845. %% get slaves
  846. SlaveNode = proplists:get_value(slave_node, Config),
  847. %% start syn on local node
  848. ok = syn:start(),
  849. %% start process
  850. Pid = syn_test_suite_helper:start_process(),
  851. %% register
  852. ok = syn:join(<<"group">>, Pid),
  853. %% start ib remote syn
  854. ok = rpc:call(SlaveNode, syn, start, []),
  855. timer:sleep(500),
  856. %% check
  857. [Pid] = syn:get_members(<<"group">>),
  858. [Pid] = rpc:call(SlaveNode, syn, get_members, [<<"group">>]).
  859. three_nodes_partial_netsplit_consistency(Config) ->
  860. GroupName = "my group",
  861. %% get slaves
  862. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  863. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  864. %% start syn on nodes
  865. ok = syn:start(),
  866. ok = rpc:call(SlaveNode1, syn, start, []),
  867. ok = rpc:call(SlaveNode2, syn, start, []),
  868. timer:sleep(100),
  869. %% start processes
  870. Pid0 = syn_test_suite_helper:start_process(),
  871. Pid0Changed = syn_test_suite_helper:start_process(),
  872. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  873. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  874. OtherPid = syn_test_suite_helper:start_process(),
  875. timer:sleep(100),
  876. %% retrieve local
  877. [] = syn:get_members("group-1"),
  878. [] = syn:get_members(GroupName),
  879. [] = syn:get_members(GroupName, with_meta),
  880. false = syn:member(Pid0, GroupName),
  881. false = syn:member(Pid0Changed, GroupName),
  882. false = syn:member(Pid1, GroupName),
  883. false = syn:member(Pid2, GroupName),
  884. %% retrieve slave 1
  885. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  886. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  887. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  888. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  889. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  890. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  891. %% retrieve slave 2
  892. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  893. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  894. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  895. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  896. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  897. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  898. %% join
  899. ok = syn:join(GroupName, Pid0),
  900. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  901. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  902. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  903. ok = syn:join("other-group", OtherPid),
  904. timer:sleep(200),
  905. %% retrieve local
  906. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  907. true = lists:sort([
  908. {Pid0, undefined},
  909. {Pid0Changed, {meta, changed}},
  910. {Pid1, undefined},
  911. {Pid2, {meta, 2}}
  912. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  913. true = syn:member(Pid0, GroupName),
  914. true = syn:member(Pid0Changed, GroupName),
  915. true = syn:member(Pid1, GroupName),
  916. true = syn:member(Pid2, GroupName),
  917. false = syn:member(OtherPid, GroupName),
  918. %% retrieve slave 1
  919. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  920. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  921. true = lists:sort([
  922. {Pid0, undefined},
  923. {Pid0Changed, {meta, changed}},
  924. {Pid1, undefined},
  925. {Pid2, {meta, 2}}
  926. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  927. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  928. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  929. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  930. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  931. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  932. %% retrieve slave 2
  933. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  934. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  935. true = lists:sort([
  936. {Pid0, undefined},
  937. {Pid0Changed, {meta, changed}},
  938. {Pid1, undefined},
  939. {Pid2, {meta, 2}}
  940. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  941. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  942. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  943. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  944. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  945. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  946. %% disconnect slave 2 from main (slave 1 can still see slave 2)
  947. syn_test_suite_helper:disconnect_node(SlaveNode2),
  948. timer:sleep(500),
  949. %% retrieve local
  950. true = lists:sort([Pid0, Pid0Changed, Pid1]) =:= lists:sort(syn:get_members(GroupName)),
  951. true = lists:sort([
  952. {Pid0, undefined},
  953. {Pid0Changed, {meta, changed}},
  954. {Pid1, undefined}
  955. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  956. true = syn:member(Pid0, GroupName),
  957. true = syn:member(Pid0Changed, GroupName),
  958. true = syn:member(Pid1, GroupName),
  959. false = syn:member(Pid2, GroupName),
  960. false = syn:member(OtherPid, GroupName),
  961. %% retrieve slave 1
  962. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  963. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  964. true = lists:sort([
  965. {Pid0, undefined},
  966. {Pid0Changed, {meta, changed}},
  967. {Pid1, undefined},
  968. {Pid2, {meta, 2}}
  969. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  970. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  971. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  972. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  973. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  974. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  975. %% disconnect slave 1
  976. syn_test_suite_helper:disconnect_node(SlaveNode1),
  977. timer:sleep(500),
  978. %% leave 0Changed
  979. ok = syn:leave(GroupName, Pid0Changed),
  980. %% retrieve local
  981. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  982. true = lists:sort([
  983. {Pid0, undefined}
  984. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  985. true = syn:member(Pid0, GroupName),
  986. false = syn:member(Pid0Changed, GroupName),
  987. false = syn:member(Pid1, GroupName),
  988. false = syn:member(Pid2, GroupName),
  989. false = syn:member(OtherPid, GroupName),
  990. %% reconnect all
  991. syn_test_suite_helper:connect_node(SlaveNode1),
  992. syn_test_suite_helper:connect_node(SlaveNode2),
  993. timer:sleep(5000),
  994. %% retrieve local
  995. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  996. true = lists:sort([
  997. {Pid0, undefined},
  998. {Pid1, undefined},
  999. {Pid2, {meta, 2}}
  1000. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1001. true = syn:member(Pid0, GroupName),
  1002. false = syn:member(Pid0Changed, GroupName),
  1003. true = syn:member(Pid1, GroupName),
  1004. true = syn:member(Pid2, GroupName),
  1005. false = syn:member(OtherPid, GroupName),
  1006. %% retrieve slave 1
  1007. true = lists:sort([Pid0, Pid1, Pid2])
  1008. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  1009. true = lists:sort([
  1010. {Pid0, undefined},
  1011. {Pid1, undefined},
  1012. {Pid2, {meta, 2}}
  1013. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  1014. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1015. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1016. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1017. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1018. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  1019. %% retrieve slave 2
  1020. true = lists:sort([Pid0, Pid1, Pid2])
  1021. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  1022. true = lists:sort([
  1023. {Pid0, undefined},
  1024. {Pid1, undefined},
  1025. {Pid2, {meta, 2}}
  1026. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1027. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1028. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1029. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1030. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1031. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]).
  1032. three_nodes_full_netsplit_consistency(Config) ->
  1033. GroupName = "my group",
  1034. %% get slaves
  1035. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1036. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1037. %% start syn on nodes
  1038. ok = syn:start(),
  1039. ok = rpc:call(SlaveNode1, syn, start, []),
  1040. ok = rpc:call(SlaveNode2, syn, start, []),
  1041. timer:sleep(100),
  1042. %% start processes
  1043. Pid0 = syn_test_suite_helper:start_process(),
  1044. Pid0Changed = syn_test_suite_helper:start_process(),
  1045. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  1046. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  1047. OtherPid = syn_test_suite_helper:start_process(),
  1048. timer:sleep(100),
  1049. %% retrieve local
  1050. [] = syn:get_members("group-1"),
  1051. [] = syn:get_members(GroupName),
  1052. [] = syn:get_members(GroupName, with_meta),
  1053. false = syn:member(Pid0, GroupName),
  1054. false = syn:member(Pid0Changed, GroupName),
  1055. false = syn:member(Pid1, GroupName),
  1056. false = syn:member(Pid2, GroupName),
  1057. %% retrieve slave 1
  1058. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  1059. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  1060. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1061. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1062. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1063. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1064. %% retrieve slave 2
  1065. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  1066. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  1067. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1068. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1069. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1070. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1071. %% join
  1072. ok = syn:join(GroupName, Pid0),
  1073. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  1074. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  1075. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  1076. ok = syn:join("other-group", OtherPid),
  1077. timer:sleep(200),
  1078. %% retrieve local
  1079. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  1080. true = lists:sort([
  1081. {Pid0, undefined},
  1082. {Pid0Changed, {meta, changed}},
  1083. {Pid1, undefined},
  1084. {Pid2, {meta, 2}}
  1085. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1086. true = syn:member(Pid0, GroupName),
  1087. true = syn:member(Pid0Changed, GroupName),
  1088. true = syn:member(Pid1, GroupName),
  1089. true = syn:member(Pid2, GroupName),
  1090. false = syn:member(OtherPid, GroupName),
  1091. %% retrieve slave 1
  1092. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  1093. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  1094. true = lists:sort([
  1095. {Pid0, undefined},
  1096. {Pid0Changed, {meta, changed}},
  1097. {Pid1, undefined},
  1098. {Pid2, {meta, 2}}
  1099. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  1100. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1101. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1102. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1103. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1104. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  1105. %% retrieve slave 2
  1106. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  1107. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  1108. true = lists:sort([
  1109. {Pid0, undefined},
  1110. {Pid0Changed, {meta, changed}},
  1111. {Pid1, undefined},
  1112. {Pid2, {meta, 2}}
  1113. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1114. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1115. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1116. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1117. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1118. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  1119. %% disconnect everyone
  1120. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1121. syn_test_suite_helper:disconnect_node(SlaveNode1),
  1122. syn_test_suite_helper:disconnect_node(SlaveNode2),
  1123. timer:sleep(2000),
  1124. %% leave 0Changed
  1125. ok = syn:leave(GroupName, Pid0Changed),
  1126. timer:sleep(500),
  1127. %% retrieve local
  1128. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  1129. true = lists:sort([
  1130. {Pid0, undefined}
  1131. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1132. true = syn:member(Pid0, GroupName),
  1133. false = syn:member(Pid0Changed, GroupName),
  1134. false = syn:member(Pid1, GroupName),
  1135. false = syn:member(Pid2, GroupName),
  1136. false = syn:member(OtherPid, GroupName),
  1137. %% reconnect all
  1138. syn_test_suite_helper:connect_node(SlaveNode1),
  1139. syn_test_suite_helper:connect_node(SlaveNode2),
  1140. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1141. timer:sleep(1500),
  1142. %% retrieve local
  1143. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  1144. true = lists:sort([
  1145. {Pid0, undefined},
  1146. {Pid1, undefined},
  1147. {Pid2, {meta, 2}}
  1148. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1149. true = syn:member(Pid0, GroupName),
  1150. false = syn:member(Pid0Changed, GroupName),
  1151. true = syn:member(Pid1, GroupName),
  1152. true = syn:member(Pid2, GroupName),
  1153. false = syn:member(OtherPid, GroupName),
  1154. %% retrieve slave 1
  1155. true = lists:sort([Pid0, Pid1, Pid2])
  1156. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  1157. true = lists:sort([
  1158. {Pid0, undefined},
  1159. {Pid1, undefined},
  1160. {Pid2, {meta, 2}}
  1161. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  1162. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1163. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1164. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1165. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1166. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  1167. %% retrieve slave 2
  1168. true = lists:sort([Pid0, Pid1, Pid2])
  1169. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  1170. true = lists:sort([
  1171. {Pid0, undefined},
  1172. {Pid1, undefined},
  1173. {Pid2, {meta, 2}}
  1174. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1175. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1176. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1177. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1178. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1179. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]).
  1180. three_nodes_anti_entropy(Config) ->
  1181. %% get slaves
  1182. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1183. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1184. %% set anti-entropy with a very low interval (0.25 second)
  1185. syn_test_suite_helper:use_anti_entropy(groups, 0.25),
  1186. rpc:call(SlaveNode1, syn_test_suite_helper, use_anti_entropy, [groups, 0.25]),
  1187. rpc:call(SlaveNode2, syn_test_suite_helper, use_anti_entropy, [groups, 0.25]),
  1188. %% start syn on nodes
  1189. ok = syn:start(),
  1190. ok = rpc:call(SlaveNode1, syn, start, []),
  1191. ok = rpc:call(SlaveNode2, syn, start, []),
  1192. timer:sleep(100),
  1193. %% start processes
  1194. Pid0 = syn_test_suite_helper:start_process(),
  1195. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  1196. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  1197. Pid2Isolated = syn_test_suite_helper:start_process(SlaveNode2),
  1198. timer:sleep(100),
  1199. %% inject data to simulate latent conflicts
  1200. ok = syn_groups:add_to_local_table("my-group", Pid0, node(), undefined),
  1201. ok = rpc:call(SlaveNode1, syn_groups, add_to_local_table, ["my-group", Pid1, SlaveNode1, undefined]),
  1202. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group", Pid2, SlaveNode2, undefined]),
  1203. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group-isolated", Pid2Isolated, SlaveNode2, undefined]),
  1204. timer:sleep(5000),
  1205. %% check
  1206. Members = lists:sort([
  1207. {Pid0, node()},
  1208. {Pid1, SlaveNode1},
  1209. {Pid2, SlaveNode2}
  1210. ]),
  1211. Members = syn:get_members("my-group", with_meta),
  1212. Members = rpc:call(SlaveNode1, syn, get_members, ["my-group", with_meta]),
  1213. Members = rpc:call(SlaveNode2, syn, get_members, ["my-group", with_meta]),
  1214. [{Pid2Isolated, SlaveNode2}] = syn:get_members("my-group-isolated", with_meta),
  1215. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode1, syn, get_members, ["my-group-isolated", with_meta]),
  1216. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode2, syn, get_members, ["my-group-isolated", with_meta]).
  1217. three_nodes_anti_entropy_manual(Config) ->
  1218. %% get slaves
  1219. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1220. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1221. %% start syn on nodes
  1222. ok = syn:start(),
  1223. ok = rpc:call(SlaveNode1, syn, start, []),
  1224. ok = rpc:call(SlaveNode2, syn, start, []),
  1225. timer:sleep(100),
  1226. %% start processes
  1227. Pid0 = syn_test_suite_helper:start_process(),
  1228. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  1229. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  1230. Pid2Isolated = syn_test_suite_helper:start_process(SlaveNode2),
  1231. timer:sleep(100),
  1232. %% inject data to simulate latent conflicts
  1233. ok = syn_groups:add_to_local_table("my-group", Pid0, node(), undefined),
  1234. ok = rpc:call(SlaveNode1, syn_groups, add_to_local_table, ["my-group", Pid1, SlaveNode1, undefined]),
  1235. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group", Pid2, SlaveNode2, undefined]),
  1236. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group-isolated", Pid2Isolated, SlaveNode2, undefined]),
  1237. %% call anti entropy
  1238. ok = syn:force_cluster_sync(groups),
  1239. timer:sleep(5000),
  1240. %% check
  1241. Members = lists:sort([
  1242. {Pid0, node()},
  1243. {Pid1, SlaveNode1},
  1244. {Pid2, SlaveNode2}
  1245. ]),
  1246. Members = syn:get_members("my-group", with_meta),
  1247. Members = rpc:call(SlaveNode1, syn, get_members, ["my-group", with_meta]),
  1248. Members = rpc:call(SlaveNode2, syn, get_members, ["my-group", with_meta]),
  1249. [{Pid2Isolated, SlaveNode2}] = syn:get_members("my-group-isolated", with_meta),
  1250. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode1, syn, get_members, ["my-group-isolated", with_meta]),
  1251. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode2, syn, get_members, ["my-group-isolated", with_meta]).