syn_groups_SUITE.erl 41 KB

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