syn_groups_SUITE.erl 43 KB

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