syn_groups_SUITE.erl 42 KB

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