syn_groups_SUITE.erl 43 KB

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