syn_groups_SUITE.erl 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  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. PidUnjoined = syn_test_suite_helper:start_process(),
  298. %% join
  299. ok = syn:join({"group-1"}, Pid),
  300. ok = syn:join({"group-1"}, Pid2),
  301. ok = syn:join({"group-1"}, Pid3),
  302. ok = syn:join({"group-2"}, Pid2),
  303. %% count
  304. 2 = syn:groups_count(),
  305. 2 = syn:groups_count(node()),
  306. %% kill & unregister
  307. ok = syn:leave({"group-1"}, Pid),
  308. syn_test_suite_helper:kill_process(Pid2),
  309. syn_test_suite_helper:kill_process(Pid3),
  310. timer:sleep(100),
  311. %% count
  312. 0 = syn:groups_count(),
  313. 0 = syn:groups_count(node()).
  314. single_node_publish(_Config) ->
  315. GroupName = "my group",
  316. Message = {test, message},
  317. %% start
  318. ok = syn:start(),
  319. %% start processes
  320. ResultPid = self(),
  321. F = fun() ->
  322. receive
  323. Message -> ResultPid ! {received, self(), Message}
  324. end
  325. end,
  326. Pid = syn_test_suite_helper:start_process(F),
  327. Pid2 = syn_test_suite_helper:start_process(F),
  328. _OtherPid = syn_test_suite_helper:start_process(F),
  329. %% join
  330. ok = syn:join(GroupName, Pid),
  331. ok = syn:join(GroupName, Pid2),
  332. true = syn:member(Pid, GroupName),
  333. true = syn:member(Pid2, GroupName),
  334. %% send
  335. {ok, 2} = syn:publish(GroupName, Message),
  336. %% check
  337. receive
  338. {received, Pid, Message} -> ok
  339. after 2000 ->
  340. ok = published_message_was_not_received_by_pid_1
  341. end,
  342. receive
  343. {received, Pid2, Message} -> ok
  344. after 2000 ->
  345. ok = published_message_was_not_received_by_pid_2
  346. end.
  347. single_node_multicall(_Config) ->
  348. GroupName = <<"my group">>,
  349. %% start
  350. ok = syn:start(),
  351. %% start processes
  352. F = fun() ->
  353. receive
  354. {syn_multi_call, RequestorPid, get_pid_name} ->
  355. syn:multi_call_reply(RequestorPid, {pong, self()})
  356. end
  357. end,
  358. Pid1 = syn_test_suite_helper:start_process(F),
  359. Pid2 = syn_test_suite_helper:start_process(F),
  360. PidUnresponsive = syn_test_suite_helper:start_process(),
  361. %% register
  362. ok = syn:join(GroupName, Pid1),
  363. ok = syn:join(GroupName, Pid2),
  364. ok = syn:join(GroupName, PidUnresponsive),
  365. %% call
  366. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name),
  367. %% check responses
  368. true = lists:sort([
  369. {Pid1, {pong, Pid1}},
  370. {Pid2, {pong, Pid2}}
  371. ]) =:= lists:sort(Replies),
  372. [PidUnresponsive] = BadPids.
  373. single_node_multicall_with_custom_timeout(_Config) ->
  374. GroupName = <<"my group">>,
  375. %% start
  376. ok = syn:start(),
  377. %% start processes
  378. F1 = fun() ->
  379. receive
  380. {syn_multi_call, RequestorPid, get_pid_name} ->
  381. syn:multi_call_reply(RequestorPid, {pong, self()})
  382. end
  383. end,
  384. Pid1 = syn_test_suite_helper:start_process(F1),
  385. F2 = fun() ->
  386. receive
  387. {syn_multi_call, RequestorPid, get_pid_name} ->
  388. timer:sleep(5000),
  389. syn:multi_call_reply(RequestorPid, {pong, self()})
  390. end
  391. end,
  392. PidTakesLong = syn_test_suite_helper:start_process(F2),
  393. PidUnresponsive = syn_test_suite_helper:start_process(),
  394. %% register
  395. ok = syn:join(GroupName, Pid1),
  396. ok = syn:join(GroupName, PidTakesLong),
  397. ok = syn:join(GroupName, PidUnresponsive),
  398. %% call
  399. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name, 2000),
  400. %% check responses
  401. [{Pid1, {pong, Pid1}}] = Replies,
  402. true = lists:sort([PidTakesLong, PidUnresponsive]) =:= lists:sort(BadPids).
  403. single_node_callback_on_process_exit(_Config) ->
  404. %% use custom handler
  405. syn_test_suite_helper:use_custom_handler(),
  406. %% start
  407. ok = syn:start(),
  408. %% start processes
  409. Pid = syn_test_suite_helper:start_process(),
  410. Pid2 = syn_test_suite_helper:start_process(),
  411. %% join
  412. TestPid = self(),
  413. ok = syn:join(group_1, Pid, {pid_group_1, TestPid}),
  414. ok = syn:join(group_2, Pid, {pid_group_2, TestPid}),
  415. ok = syn:join(group_1, Pid2, {pid2, TestPid}),
  416. %% kill 1
  417. syn_test_suite_helper:kill_process(Pid),
  418. receive
  419. {received_event_on, pid_group_1} ->
  420. ok;
  421. {received_event_on, pid2} ->
  422. ok = callback_on_process_exit_was_received_by_pid2
  423. after 1000 ->
  424. ok = callback_on_process_exit_was_not_received_by_pid
  425. end,
  426. receive
  427. {received_event_on, pid_group_2} ->
  428. ok;
  429. {received_event_on, pid2} ->
  430. ok = callback_on_process_exit_was_received_by_pid2
  431. after 1000 ->
  432. ok = callback_on_process_exit_was_not_received_by_pid
  433. end,
  434. %% unregister & kill 2
  435. ok = syn:leave(group_1, Pid2),
  436. syn_test_suite_helper:kill_process(Pid2),
  437. receive
  438. {received_event_on, pid2} ->
  439. ok = callback_on_process_exit_was_received_by_pid2
  440. after 1000 ->
  441. ok
  442. end.
  443. single_node_monitor_after_group_crash(_Config) ->
  444. GroupName = "my group",
  445. %% start
  446. ok = syn:start(),
  447. %% start processes
  448. Pid = syn_test_suite_helper:start_process(),
  449. %% join
  450. ok = syn:join(GroupName, Pid),
  451. %% kill groups
  452. exit(whereis(syn_groups), kill),
  453. timer:sleep(200),
  454. %% retrieve
  455. true = syn:member(Pid, GroupName),
  456. [Pid] = syn:get_members(GroupName),
  457. %% kill process
  458. syn_test_suite_helper:kill_process(Pid),
  459. timer:sleep(200),
  460. %% retrieve
  461. false = syn:member(Pid, GroupName),
  462. [] = syn:get_members(GroupName).
  463. two_nodes_join_monitor_and_unregister(Config) ->
  464. GroupName = "my group",
  465. %% get slave
  466. SlaveNode = proplists:get_value(slave_node, Config),
  467. %% start
  468. ok = syn:start(),
  469. ok = rpc:call(SlaveNode, syn, start, []),
  470. timer:sleep(100),
  471. %% start processes
  472. LocalPid = syn_test_suite_helper:start_process(),
  473. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  474. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  475. OtherPid = syn_test_suite_helper:start_process(),
  476. %% retrieve
  477. [] = syn:get_members("group-1"),
  478. [] = syn:get_members(GroupName),
  479. [] = syn:get_members(GroupName, with_meta),
  480. false = syn:member(LocalPid, GroupName),
  481. false = syn:member(RemotePid, GroupName),
  482. false = syn:member(RemotePidJoinRemote, GroupName),
  483. false = syn:member(OtherPid, GroupName),
  484. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  485. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  486. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  487. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  488. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  489. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  490. %% join
  491. ok = syn:join(GroupName, LocalPid),
  492. ok = syn:join(GroupName, RemotePid, {with_meta}),
  493. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  494. ok = syn:join("other-group", OtherPid),
  495. timer:sleep(200),
  496. %% retrieve local
  497. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote]) =:= lists:sort(syn:get_members(GroupName)),
  498. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  499. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  500. true = syn:member(LocalPid, GroupName),
  501. true = syn:member(RemotePid, GroupName),
  502. true = syn:member(RemotePidJoinRemote, GroupName),
  503. false = syn:member(OtherPid, GroupName),
  504. %% retrieve remote
  505. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote])
  506. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName])),
  507. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  508. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta])),
  509. true = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  510. true = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  511. true = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  512. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  513. %% leave & kill
  514. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  515. ok = syn:leave(GroupName, RemotePid),
  516. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  517. syn_test_suite_helper:kill_process(OtherPid),
  518. timer:sleep(200),
  519. %% retrieve
  520. [] = syn:get_members("group-1"),
  521. [] = syn:get_members(GroupName),
  522. [] = syn:get_members(GroupName, with_meta),
  523. false = syn:member(LocalPid, GroupName),
  524. false = syn:member(RemotePid, GroupName),
  525. false = syn:member(RemotePidJoinRemote, GroupName),
  526. false = syn:member(OtherPid, GroupName),
  527. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  528. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  529. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  530. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  531. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  532. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]).
  533. two_nodes_local_members(Config) ->
  534. GroupName = "my group",
  535. %% get slave
  536. SlaveNode = proplists:get_value(slave_node, Config),
  537. %% start
  538. ok = syn:start(),
  539. ok = rpc:call(SlaveNode, syn, start, []),
  540. timer:sleep(100),
  541. %% start processes
  542. LocalPid = syn_test_suite_helper:start_process(),
  543. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  544. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  545. OtherPid = syn_test_suite_helper:start_process(),
  546. %% local members
  547. [] = syn:get_local_members(GroupName),
  548. [] = syn:get_local_members(GroupName, with_meta),
  549. false = syn:local_member(LocalPid, GroupName),
  550. false = syn:local_member(RemotePid, GroupName),
  551. false = syn:local_member(RemotePidJoinRemote, GroupName),
  552. false = syn:local_member(OtherPid, GroupName),
  553. %% remote members
  554. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  555. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]),
  556. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  557. false = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  558. false = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  559. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  560. %% join
  561. ok = syn:join(GroupName, LocalPid),
  562. ok = syn:join(GroupName, RemotePid, {meta, 2}),
  563. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  564. ok = syn:join({"other-group"}, OtherPid),
  565. timer:sleep(200),
  566. %% local members
  567. [LocalPid] = syn:get_local_members(GroupName),
  568. [{LocalPid, undefined}] = syn:get_local_members(GroupName, with_meta),
  569. [OtherPid] = syn:get_local_members({"other-group"}),
  570. true = syn:local_member(LocalPid, GroupName),
  571. false = syn:local_member(RemotePid, GroupName),
  572. false = syn:local_member(RemotePidJoinRemote, GroupName),
  573. false = syn:local_member(OtherPid, GroupName),
  574. true = syn:local_member(OtherPid, {"other-group"}),
  575. %% remote members
  576. true = lists:sort([RemotePid, RemotePidJoinRemote])
  577. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName])),
  578. true = lists:sort([{RemotePid, {meta, 2}}, {RemotePidJoinRemote, undefined}])
  579. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta])),
  580. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  581. true = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  582. true = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  583. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  584. %% leave & kill
  585. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  586. ok = syn:leave(GroupName, RemotePid),
  587. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  588. syn_test_suite_helper:kill_process(OtherPid),
  589. timer:sleep(200),
  590. %% local members
  591. [] = syn:get_local_members(GroupName),
  592. [] = syn:get_local_members(GroupName, with_meta),
  593. %% remote members
  594. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  595. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]).
  596. two_nodes_groups_count(Config) ->
  597. %% get slave
  598. SlaveNode = proplists:get_value(slave_node, Config),
  599. %% start
  600. ok = syn:start(),
  601. ok = rpc:call(SlaveNode, syn, start, []),
  602. timer:sleep(100),
  603. %% start processes
  604. LocalPid = syn_test_suite_helper:start_process(),
  605. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  606. RemotePidRegRemote = syn_test_suite_helper:start_process(SlaveNode),
  607. _PidUnjoined = syn_test_suite_helper:start_process(),
  608. %% join
  609. ok = syn:join(<<"local group">>, LocalPid),
  610. ok = syn:join(<<"remote group">>, RemotePid),
  611. ok = rpc:call(SlaveNode, syn, join, [<<"remote group join_remote">>, RemotePidRegRemote]),
  612. timer:sleep(500),
  613. %% count
  614. 3 = syn:groups_count(),
  615. 1 = syn:groups_count(node()),
  616. 2 = syn:groups_count(SlaveNode),
  617. %% kill & unregister processes
  618. syn_test_suite_helper:kill_process(LocalPid),
  619. ok = syn:leave(<<"remote group">>, RemotePid),
  620. syn_test_suite_helper:kill_process(RemotePidRegRemote),
  621. timer:sleep(100),
  622. %% count
  623. 0 = syn:groups_count(),
  624. 0 = syn:groups_count(node()),
  625. 0 = syn:groups_count(SlaveNode).
  626. two_nodes_publish(Config) ->
  627. GroupName = "my group",
  628. Message = {test, message},
  629. %% get slave
  630. SlaveNode = proplists:get_value(slave_node, Config),
  631. %% start
  632. ok = syn:start(),
  633. ok = rpc:call(SlaveNode, syn, start, []),
  634. timer:sleep(100),
  635. %% start processes
  636. ResultPid = self(),
  637. F = fun() ->
  638. receive
  639. Message -> ResultPid ! {received, self(), Message}
  640. end
  641. end,
  642. LocalPid = syn_test_suite_helper:start_process(F),
  643. LocalPid2 = syn_test_suite_helper:start_process(F),
  644. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  645. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  646. OtherPid = syn_test_suite_helper:start_process(F),
  647. %% join
  648. ok = syn:join(GroupName, LocalPid),
  649. ok = syn:join(GroupName, LocalPid2),
  650. ok = syn:join(GroupName, RemotePid),
  651. ok = syn:join(GroupName, RemotePid2),
  652. timer:sleep(200),
  653. %% send
  654. {ok, 4} = syn:publish(GroupName, Message),
  655. %% check
  656. receive
  657. {received, LocalPid, Message} -> ok
  658. after 2000 ->
  659. ok = published_message_was_not_received_by_local_pid
  660. end,
  661. receive
  662. {received, LocalPid2, Message} -> ok
  663. after 2000 ->
  664. ok = published_message_was_not_received_by_local_pid_2
  665. end,
  666. receive
  667. {received, RemotePid, Message} -> ok
  668. after 2000 ->
  669. ok = published_message_was_not_received_by_remote_pid
  670. end,
  671. receive
  672. {received, RemotePid2, Message} -> ok
  673. after 2000 ->
  674. ok = published_message_was_not_received_by_remote_pid_2
  675. end,
  676. receive
  677. {received, OtherPid, Message} ->
  678. ok = published_message_was_received_by_other_pid
  679. after 250 ->
  680. ok
  681. end.
  682. two_nodes_local_publish(Config) ->
  683. GroupName = "my group",
  684. Message = {test, message},
  685. %% get slave
  686. SlaveNode = proplists:get_value(slave_node, Config),
  687. %% start
  688. ok = syn:start(),
  689. ok = rpc:call(SlaveNode, syn, start, []),
  690. timer:sleep(100),
  691. %% start processes
  692. ResultPid = self(),
  693. F = fun() ->
  694. receive
  695. Message -> ResultPid ! {received, self(), Message}
  696. end
  697. end,
  698. LocalPid = syn_test_suite_helper:start_process(F),
  699. LocalPid2 = syn_test_suite_helper:start_process(F),
  700. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  701. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  702. OtherPid = syn_test_suite_helper:start_process(F),
  703. %% join
  704. ok = syn:join(GroupName, LocalPid),
  705. ok = syn:join(GroupName, LocalPid2),
  706. ok = syn:join(GroupName, RemotePid),
  707. ok = syn:join(GroupName, RemotePid2),
  708. timer:sleep(200),
  709. %% send
  710. {ok, 2} = syn:publish_to_local(GroupName, Message),
  711. %% check
  712. receive
  713. {received, LocalPid, Message} -> ok
  714. after 2000 ->
  715. ok = published_message_was_not_received_by_local_pid
  716. end,
  717. receive
  718. {received, LocalPid2, Message} -> ok
  719. after 2000 ->
  720. ok = published_message_was_not_received_by_local_pid_2
  721. end,
  722. receive
  723. {received, RemotePid, Message} ->
  724. ok = published_message_was_received_by_remote_pid
  725. after 250 ->
  726. ok
  727. end,
  728. receive
  729. {received, RemotePid, Message} ->
  730. ok = published_message_was_received_by_remote_pid_2
  731. after 250 ->
  732. ok
  733. end,
  734. receive
  735. {received, OtherPid, Message} ->
  736. ok = published_message_was_received_by_other_pid
  737. after 250 ->
  738. ok
  739. end.
  740. two_nodes_multicall(Config) ->
  741. GroupName = <<"my group">>,
  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. F = fun() ->
  750. receive
  751. {syn_multi_call, RequestorPid, get_pid_name} ->
  752. syn:multi_call_reply(RequestorPid, {pong, self()})
  753. end
  754. end,
  755. Pid1 = syn_test_suite_helper:start_process(F),
  756. Pid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  757. PidUnresponsive = syn_test_suite_helper:start_process(),
  758. %% register
  759. ok = syn:join(GroupName, Pid1),
  760. ok = syn:join(GroupName, Pid2),
  761. ok = syn:join(GroupName, PidUnresponsive),
  762. timer:sleep(500),
  763. %% call
  764. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name),
  765. %% check responses
  766. true = lists:sort([
  767. {Pid1, {pong, Pid1}},
  768. {Pid2, {pong, Pid2}}
  769. ]) =:= lists:sort(Replies),
  770. [PidUnresponsive] = BadPids.
  771. two_nodes_groups_full_cluster_sync_on_boot_node_added_later(_Config) ->
  772. %% stop slave
  773. syn_test_suite_helper:stop_slave(syn_slave),
  774. %% start syn on local node
  775. ok = syn:start(),
  776. %% start process
  777. Pid = syn_test_suite_helper:start_process(),
  778. %% register
  779. ok = syn:join(<<"group">>, Pid),
  780. %% start remote node and syn
  781. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  782. ok = rpc:call(SlaveNode, syn, start, []),
  783. timer:sleep(1000),
  784. %% check
  785. [Pid] = syn:get_members(<<"group">>),
  786. [Pid] = rpc:call(SlaveNode, syn, get_members, [<<"group">>]).
  787. two_nodes_groups_full_cluster_sync_on_boot_syn_started_later(Config) ->
  788. %% get slaves
  789. SlaveNode = proplists:get_value(slave_node, Config),
  790. %% start syn on local node
  791. ok = syn:start(),
  792. %% start process
  793. Pid = syn_test_suite_helper:start_process(),
  794. %% register
  795. ok = syn:join(<<"group">>, Pid),
  796. %% start ib remote syn
  797. ok = rpc:call(SlaveNode, syn, start, []),
  798. timer:sleep(500),
  799. %% check
  800. [Pid] = syn:get_members(<<"group">>),
  801. [Pid] = rpc:call(SlaveNode, syn, get_members, [<<"group">>]).
  802. three_nodes_partial_netsplit_consistency(Config) ->
  803. GroupName = "my group",
  804. %% get slaves
  805. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  806. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  807. %% start syn on nodes
  808. ok = syn:start(),
  809. ok = rpc:call(SlaveNode1, syn, start, []),
  810. ok = rpc:call(SlaveNode2, syn, start, []),
  811. timer:sleep(100),
  812. %% start processes
  813. Pid0 = syn_test_suite_helper:start_process(),
  814. Pid0Changed = syn_test_suite_helper:start_process(),
  815. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  816. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  817. OtherPid = syn_test_suite_helper:start_process(),
  818. timer:sleep(100),
  819. %% retrieve local
  820. [] = syn:get_members("group-1"),
  821. [] = syn:get_members(GroupName),
  822. [] = syn:get_members(GroupName, with_meta),
  823. false = syn:member(Pid0, GroupName),
  824. false = syn:member(Pid0Changed, GroupName),
  825. false = syn:member(Pid1, GroupName),
  826. false = syn:member(Pid2, GroupName),
  827. %% retrieve slave 1
  828. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  829. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  830. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  831. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  832. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  833. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  834. %% retrieve slave 2
  835. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  836. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  837. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  838. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  839. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  840. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  841. %% join
  842. ok = syn:join(GroupName, Pid0),
  843. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  844. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  845. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  846. ok = syn:join("other-group", OtherPid),
  847. timer:sleep(200),
  848. %% retrieve local
  849. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  850. true = lists:sort([
  851. {Pid0, undefined},
  852. {Pid0Changed, {meta, changed}},
  853. {Pid1, undefined},
  854. {Pid2, {meta, 2}}
  855. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  856. true = syn:member(Pid0, GroupName),
  857. true = syn:member(Pid0Changed, GroupName),
  858. true = syn:member(Pid1, GroupName),
  859. true = syn:member(Pid2, GroupName),
  860. false = syn:member(OtherPid, GroupName),
  861. %% retrieve slave 1
  862. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  863. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  864. true = lists:sort([
  865. {Pid0, undefined},
  866. {Pid0Changed, {meta, changed}},
  867. {Pid1, undefined},
  868. {Pid2, {meta, 2}}
  869. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  870. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  871. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  872. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  873. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  874. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  875. %% retrieve slave 2
  876. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  877. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  878. true = lists:sort([
  879. {Pid0, undefined},
  880. {Pid0Changed, {meta, changed}},
  881. {Pid1, undefined},
  882. {Pid2, {meta, 2}}
  883. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  884. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  885. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  886. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  887. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  888. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  889. %% disconnect slave 2 from main (slave 1 can still see slave 2)
  890. syn_test_suite_helper:disconnect_node(SlaveNode2),
  891. timer:sleep(500),
  892. %% retrieve local
  893. true = lists:sort([Pid0, Pid0Changed, Pid1]) =:= lists:sort(syn:get_members(GroupName)),
  894. true = lists:sort([
  895. {Pid0, undefined},
  896. {Pid0Changed, {meta, changed}},
  897. {Pid1, undefined}
  898. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  899. true = syn:member(Pid0, GroupName),
  900. true = syn:member(Pid0Changed, GroupName),
  901. true = syn:member(Pid1, GroupName),
  902. false = syn:member(Pid2, GroupName),
  903. false = syn:member(OtherPid, GroupName),
  904. %% retrieve slave 1
  905. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  906. =:= lists:sort(rpc:call(SlaveNode1, 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(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  913. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  914. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  915. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  916. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  917. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  918. %% disconnect slave 1
  919. syn_test_suite_helper:disconnect_node(SlaveNode1),
  920. timer:sleep(500),
  921. %% leave 0Changed
  922. ok = syn:leave(GroupName, Pid0Changed),
  923. %% retrieve local
  924. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  925. true = lists:sort([
  926. {Pid0, undefined}
  927. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  928. true = syn:member(Pid0, GroupName),
  929. false = syn:member(Pid0Changed, GroupName),
  930. false = syn:member(Pid1, GroupName),
  931. false = syn:member(Pid2, GroupName),
  932. false = syn:member(OtherPid, GroupName),
  933. %% reconnect all
  934. syn_test_suite_helper:connect_node(SlaveNode1),
  935. syn_test_suite_helper:connect_node(SlaveNode2),
  936. timer:sleep(5000),
  937. %% retrieve local
  938. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  939. true = lists:sort([
  940. {Pid0, undefined},
  941. {Pid1, undefined},
  942. {Pid2, {meta, 2}}
  943. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  944. true = syn:member(Pid0, GroupName),
  945. false = syn:member(Pid0Changed, GroupName),
  946. true = syn:member(Pid1, GroupName),
  947. true = syn:member(Pid2, GroupName),
  948. false = syn:member(OtherPid, GroupName),
  949. %% retrieve slave 1
  950. true = lists:sort([Pid0, Pid1, Pid2])
  951. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  952. true = lists:sort([
  953. {Pid0, undefined},
  954. {Pid1, undefined},
  955. {Pid2, {meta, 2}}
  956. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  957. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  958. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  959. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  960. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  961. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  962. %% retrieve slave 2
  963. true = lists:sort([Pid0, Pid1, Pid2])
  964. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  965. true = lists:sort([
  966. {Pid0, undefined},
  967. {Pid1, undefined},
  968. {Pid2, {meta, 2}}
  969. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  970. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  971. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  972. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  973. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  974. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]).
  975. three_nodes_full_netsplit_consistency(Config) ->
  976. GroupName = "my group",
  977. %% get slaves
  978. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  979. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  980. %% start syn on nodes
  981. ok = syn:start(),
  982. ok = rpc:call(SlaveNode1, syn, start, []),
  983. ok = rpc:call(SlaveNode2, syn, start, []),
  984. timer:sleep(100),
  985. %% start processes
  986. Pid0 = syn_test_suite_helper:start_process(),
  987. Pid0Changed = syn_test_suite_helper:start_process(),
  988. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  989. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  990. OtherPid = syn_test_suite_helper:start_process(),
  991. timer:sleep(100),
  992. %% retrieve local
  993. [] = syn:get_members("group-1"),
  994. [] = syn:get_members(GroupName),
  995. [] = syn:get_members(GroupName, with_meta),
  996. false = syn:member(Pid0, GroupName),
  997. false = syn:member(Pid0Changed, GroupName),
  998. false = syn:member(Pid1, GroupName),
  999. false = syn:member(Pid2, GroupName),
  1000. %% retrieve slave 1
  1001. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  1002. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  1003. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1004. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1005. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1006. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1007. %% retrieve slave 2
  1008. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  1009. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  1010. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1011. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1012. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1013. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1014. %% join
  1015. ok = syn:join(GroupName, Pid0),
  1016. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  1017. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  1018. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  1019. ok = syn:join("other-group", OtherPid),
  1020. timer:sleep(200),
  1021. %% retrieve local
  1022. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  1023. true = lists:sort([
  1024. {Pid0, undefined},
  1025. {Pid0Changed, {meta, changed}},
  1026. {Pid1, undefined},
  1027. {Pid2, {meta, 2}}
  1028. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1029. true = syn:member(Pid0, GroupName),
  1030. true = syn:member(Pid0Changed, GroupName),
  1031. true = syn:member(Pid1, GroupName),
  1032. true = syn:member(Pid2, GroupName),
  1033. false = syn:member(OtherPid, GroupName),
  1034. %% retrieve slave 1
  1035. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  1036. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  1037. true = lists:sort([
  1038. {Pid0, undefined},
  1039. {Pid0Changed, {meta, changed}},
  1040. {Pid1, undefined},
  1041. {Pid2, {meta, 2}}
  1042. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  1043. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1044. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1045. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1046. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1047. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  1048. %% retrieve slave 2
  1049. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  1050. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  1051. true = lists:sort([
  1052. {Pid0, undefined},
  1053. {Pid0Changed, {meta, changed}},
  1054. {Pid1, undefined},
  1055. {Pid2, {meta, 2}}
  1056. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1057. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1058. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1059. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1060. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1061. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  1062. %% disconnect everyone
  1063. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1064. syn_test_suite_helper:disconnect_node(SlaveNode1),
  1065. syn_test_suite_helper:disconnect_node(SlaveNode2),
  1066. timer:sleep(2000),
  1067. %% leave 0Changed
  1068. ok = syn:leave(GroupName, Pid0Changed),
  1069. timer:sleep(250),
  1070. %% retrieve local
  1071. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  1072. true = lists:sort([
  1073. {Pid0, undefined}
  1074. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1075. true = syn:member(Pid0, GroupName),
  1076. false = syn:member(Pid0Changed, GroupName),
  1077. false = syn:member(Pid1, GroupName),
  1078. false = syn:member(Pid2, GroupName),
  1079. false = syn:member(OtherPid, GroupName),
  1080. %% reconnect all
  1081. syn_test_suite_helper:connect_node(SlaveNode1),
  1082. syn_test_suite_helper:connect_node(SlaveNode2),
  1083. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1084. timer:sleep(1500),
  1085. %% retrieve local
  1086. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  1087. true = lists:sort([
  1088. {Pid0, undefined},
  1089. {Pid1, undefined},
  1090. {Pid2, {meta, 2}}
  1091. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1092. true = syn:member(Pid0, GroupName),
  1093. false = syn:member(Pid0Changed, GroupName),
  1094. true = syn:member(Pid1, GroupName),
  1095. true = syn:member(Pid2, GroupName),
  1096. false = syn:member(OtherPid, GroupName),
  1097. %% retrieve slave 1
  1098. true = lists:sort([Pid0, Pid1, Pid2])
  1099. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  1100. true = lists:sort([
  1101. {Pid0, undefined},
  1102. {Pid1, undefined},
  1103. {Pid2, {meta, 2}}
  1104. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  1105. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1106. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1107. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1108. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1109. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  1110. %% retrieve slave 2
  1111. true = lists:sort([Pid0, Pid1, Pid2])
  1112. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  1113. true = lists:sort([
  1114. {Pid0, undefined},
  1115. {Pid1, undefined},
  1116. {Pid2, {meta, 2}}
  1117. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1118. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1119. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1120. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1121. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1122. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]).
  1123. three_nodes_anti_entropy(Config) ->
  1124. %% get slaves
  1125. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1126. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1127. %% set anti-entropy with a very low interval (0.25 second)
  1128. syn_test_suite_helper:use_anti_entropy(groups, 0.25),
  1129. rpc:call(SlaveNode1, syn_test_suite_helper, use_anti_entropy, [groups, 0.25]),
  1130. rpc:call(SlaveNode2, syn_test_suite_helper, use_anti_entropy, [groups, 0.25]),
  1131. %% start syn on nodes
  1132. ok = syn:start(),
  1133. ok = rpc:call(SlaveNode1, syn, start, []),
  1134. ok = rpc:call(SlaveNode2, syn, start, []),
  1135. timer:sleep(100),
  1136. %% start processes
  1137. Pid0 = syn_test_suite_helper:start_process(),
  1138. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  1139. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  1140. Pid2Isolated = syn_test_suite_helper:start_process(SlaveNode2),
  1141. timer:sleep(100),
  1142. %% inject data to simulate latent conflicts
  1143. ok = syn_groups:add_to_local_table("my-group", Pid0, node(), undefined),
  1144. ok = rpc:call(SlaveNode1, syn_groups, add_to_local_table, ["my-group", Pid1, SlaveNode1, undefined]),
  1145. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group", Pid2, SlaveNode2, undefined]),
  1146. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group-isolated", Pid2Isolated, SlaveNode2, undefined]),
  1147. timer:sleep(5000),
  1148. %% check
  1149. Members = lists:sort([
  1150. {Pid0, node()},
  1151. {Pid1, SlaveNode1},
  1152. {Pid2, SlaveNode2}
  1153. ]),
  1154. Members = syn:get_members("my-group", with_meta),
  1155. Members = rpc:call(SlaveNode1, syn, get_members, ["my-group", with_meta]),
  1156. Members = rpc:call(SlaveNode2, syn, get_members, ["my-group", with_meta]),
  1157. [{Pid2Isolated, SlaveNode2}] = syn:get_members("my-group-isolated", with_meta),
  1158. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode1, syn, get_members, ["my-group-isolated", with_meta]),
  1159. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode2, syn, get_members, ["my-group-isolated", with_meta]).
  1160. three_nodes_anti_entropy_manual(Config) ->
  1161. %% get slaves
  1162. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1163. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1164. %% start syn on nodes
  1165. ok = syn:start(),
  1166. ok = rpc:call(SlaveNode1, syn, start, []),
  1167. ok = rpc:call(SlaveNode2, syn, start, []),
  1168. timer:sleep(100),
  1169. %% start processes
  1170. Pid0 = syn_test_suite_helper:start_process(),
  1171. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  1172. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  1173. Pid2Isolated = syn_test_suite_helper:start_process(SlaveNode2),
  1174. timer:sleep(100),
  1175. %% inject data to simulate latent conflicts
  1176. ok = syn_groups:add_to_local_table("my-group", Pid0, node(), undefined),
  1177. ok = rpc:call(SlaveNode1, syn_groups, add_to_local_table, ["my-group", Pid1, SlaveNode1, undefined]),
  1178. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group", Pid2, SlaveNode2, undefined]),
  1179. ok = rpc:call(SlaveNode2, syn_groups, add_to_local_table, ["my-group-isolated", Pid2Isolated, SlaveNode2, undefined]),
  1180. %% call anti entropy
  1181. ok = syn:force_cluster_sync(groups),
  1182. timer:sleep(5000),
  1183. %% check
  1184. Members = lists:sort([
  1185. {Pid0, node()},
  1186. {Pid1, SlaveNode1},
  1187. {Pid2, SlaveNode2}
  1188. ]),
  1189. Members = syn:get_members("my-group", with_meta),
  1190. Members = rpc:call(SlaveNode1, syn, get_members, ["my-group", with_meta]),
  1191. Members = rpc:call(SlaveNode2, syn, get_members, ["my-group", with_meta]),
  1192. [{Pid2Isolated, SlaveNode2}] = syn:get_members("my-group-isolated", with_meta),
  1193. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode1, syn, get_members, ["my-group-isolated", with_meta]),
  1194. [{Pid2Isolated, SlaveNode2}] = rpc:call(SlaveNode2, syn, get_members, ["my-group-isolated", with_meta]).