syn_groups_SUITE.erl 38 KB

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