syn_groups_SUITE.erl 49 KB

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