syn_groups_SUITE.erl 33 KB

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