syn_groups_SUITE.erl 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. %% ==========================================================================================================
  2. %% Syn - A global Process Registry and Process Group manager.
  3. %%
  4. %% The MIT License (MIT)
  5. %%
  6. %% Copyright (c) 2015-2019 Roberto Ostinelli <roberto@ostinelli.net> and Neato Robotics, Inc.
  7. %%
  8. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  9. %% of this software and associated documentation files (the "Software"), to deal
  10. %% in the Software without restriction, including without limitation the rights
  11. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. %% copies of the Software, and to permit persons to whom the Software is
  13. %% furnished to do so, subject to the following conditions:
  14. %%
  15. %% The above copyright notice and this permission notice shall be included in
  16. %% all copies or substantial portions of the Software.
  17. %%
  18. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. %% THE SOFTWARE.
  25. %% ==========================================================================================================
  26. -module(syn_groups_SUITE).
  27. %% callbacks
  28. -export([all/0]).
  29. -export([init_per_suite/1, end_per_suite/1]).
  30. -export([groups/0, init_per_group/2, end_per_group/2]).
  31. -export([init_per_testcase/2, end_per_testcase/2]).
  32. %% tests
  33. -export([
  34. single_node_join_and_monitor/1,
  35. single_node_join_and_leave/1,
  36. single_node_join_errors/1,
  37. single_node_publish/1
  38. ]).
  39. -export([
  40. two_nodes_join_monitor_and_unregister/1,
  41. two_nodes_local_members/1,
  42. two_nodes_publish/1
  43. ]).
  44. -export([
  45. three_nodes_partial_netsplit_consistency/1,
  46. three_nodes_full_netsplit_consistency/1
  47. ]).
  48. %% include
  49. -include_lib("common_test/include/ct.hrl").
  50. %% ===================================================================
  51. %% Callbacks
  52. %% ===================================================================
  53. %% -------------------------------------------------------------------
  54. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  55. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  56. %% GroupName = atom()
  57. %% TestCase = atom()
  58. %% Reason = any()
  59. %% -------------------------------------------------------------------
  60. all() ->
  61. [
  62. {group, single_node_groups},
  63. {group, two_nodes_groups},
  64. {group, three_nodes_groups}
  65. ].
  66. %% -------------------------------------------------------------------
  67. %% Function: groups() -> [Group]
  68. %% Group = {GroupName,Properties,GroupsAndTestCases}
  69. %% GroupName = atom()
  70. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  71. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  72. %% TestCase = atom()
  73. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  74. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  75. %% repeat_until_any_ok | repeat_until_any_fail
  76. %% N = integer() | forever
  77. %% -------------------------------------------------------------------
  78. groups() ->
  79. [
  80. {single_node_groups, [shuffle], [
  81. single_node_join_and_monitor,
  82. single_node_join_and_leave,
  83. single_node_join_errors,
  84. single_node_publish
  85. ]},
  86. {two_nodes_groups, [shuffle], [
  87. two_nodes_join_monitor_and_unregister,
  88. two_nodes_local_members,
  89. two_nodes_publish
  90. ]},
  91. {three_nodes_groups, [shuffle], [
  92. three_nodes_partial_netsplit_consistency,
  93. three_nodes_full_netsplit_consistency
  94. ]}
  95. ].
  96. %% -------------------------------------------------------------------
  97. %% Function: init_per_suite(Config0) ->
  98. %% Config1 | {skip,Reason} |
  99. %% {skip_and_save,Reason,Config1}
  100. %% Config0 = Config1 = [tuple()]
  101. %% Reason = any()
  102. %% -------------------------------------------------------------------
  103. init_per_suite(Config) ->
  104. Config.
  105. %% -------------------------------------------------------------------
  106. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  107. %% Config0 = Config1 = [tuple()]
  108. %% -------------------------------------------------------------------
  109. end_per_suite(_Config) ->
  110. ok.
  111. %% -------------------------------------------------------------------
  112. %% Function: init_per_group(GroupName, Config0) ->
  113. %% Config1 | {skip,Reason} |
  114. %% {skip_and_save,Reason,Config1}
  115. %% GroupName = atom()
  116. %% Config0 = Config1 = [tuple()]
  117. %% Reason = any()
  118. %% -------------------------------------------------------------------
  119. init_per_group(two_nodes_groups, Config) ->
  120. %% start slave
  121. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  122. %% config
  123. [{slave_node, SlaveNode} | Config];
  124. init_per_group(three_nodes_groups, Config) ->
  125. %% start slave
  126. {ok, SlaveNode1} = syn_test_suite_helper:start_slave(syn_slave_1),
  127. {ok, SlaveNode2} = syn_test_suite_helper:start_slave(syn_slave_2),
  128. %% config
  129. [{slave_node_1, SlaveNode1}, {slave_node_2, SlaveNode2} | Config];
  130. init_per_group(_GroupName, Config) ->
  131. Config.
  132. %% -------------------------------------------------------------------
  133. %% Function: end_per_group(GroupName, Config0) ->
  134. %% void() | {save_config,Config1}
  135. %% GroupName = atom()
  136. %% Config0 = Config1 = [tuple()]
  137. %% -------------------------------------------------------------------
  138. end_per_group(two_nodes_groups, Config) ->
  139. SlaveNode = proplists:get_value(slave_node, Config),
  140. syn_test_suite_helper:connect_node(SlaveNode),
  141. syn_test_suite_helper:stop_slave(syn_slave),
  142. timer:sleep(1000);
  143. end_per_group(three_nodes_groups, Config) ->
  144. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  145. syn_test_suite_helper:connect_node(SlaveNode1),
  146. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  147. syn_test_suite_helper:connect_node(SlaveNode2),
  148. syn_test_suite_helper:stop_slave(syn_slave_1),
  149. syn_test_suite_helper:stop_slave(syn_slave_2),
  150. timer:sleep(1000);
  151. end_per_group(_GroupName, _Config) ->
  152. ok.
  153. %% -------------------------------------------------------------------
  154. %% Function: init_per_testcase(TestCase, Config0) ->
  155. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  156. %% TestCase = atom()
  157. %% Config0 = Config1 = [tuple()]
  158. %% Reason = any()
  159. %% -------------------------------------------------------------------
  160. init_per_testcase(_TestCase, Config) ->
  161. Config.
  162. %% -------------------------------------------------------------------
  163. %% Function: end_per_testcase(TestCase, Config0) ->
  164. %% void() | {save_config,Config1} | {fail,Reason}
  165. %% TestCase = atom()
  166. %% Config0 = Config1 = [tuple()]
  167. %% Reason = any()
  168. %% -------------------------------------------------------------------
  169. end_per_testcase(_, _Config) ->
  170. syn_test_suite_helper:clean_after_test().
  171. %% ===================================================================
  172. %% Tests
  173. %% ===================================================================
  174. single_node_join_and_monitor(_Config) ->
  175. GroupName = "my group",
  176. %% start
  177. ok = syn:start(),
  178. %% start processes
  179. Pid = syn_test_suite_helper:start_process(),
  180. PidWithMeta = syn_test_suite_helper:start_process(),
  181. PidOther = syn_test_suite_helper:start_process(),
  182. %% retrieve
  183. [] = syn:get_members(GroupName),
  184. [] = syn:get_members(GroupName, with_meta),
  185. false = syn:member(Pid, GroupName),
  186. false = syn:member(PidWithMeta, GroupName),
  187. false = syn:member(PidOther, GroupName),
  188. %% join
  189. ok = syn:join(GroupName, Pid),
  190. ok = syn:join(GroupName, PidWithMeta, {with, meta}),
  191. ok = syn:join("other-group", PidOther),
  192. %% retrieve
  193. true = syn:member(Pid, GroupName),
  194. true = syn:member(PidWithMeta, GroupName),
  195. false = syn:member(PidOther, GroupName),
  196. true = lists:sort([Pid, PidWithMeta]) =:= lists:sort(syn:get_members(GroupName)),
  197. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with, meta}}])
  198. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  199. %% re-join
  200. ok = syn:join(GroupName, PidWithMeta, {with2, meta2}),
  201. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with2, meta2}}])
  202. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  203. %% kill process
  204. syn_test_suite_helper:kill_process(Pid),
  205. syn_test_suite_helper:kill_process(PidWithMeta),
  206. syn_test_suite_helper:kill_process(PidOther),
  207. timer:sleep(100),
  208. %% retrieve
  209. [] = syn:get_members(GroupName),
  210. [] = syn:get_members(GroupName, with_meta),
  211. false = syn:member(Pid, GroupName),
  212. false = syn:member(PidWithMeta, GroupName).
  213. single_node_join_and_leave(_Config) ->
  214. GroupName = "my group",
  215. %% start
  216. ok = syn:start(),
  217. %% start processes
  218. Pid = syn_test_suite_helper:start_process(),
  219. PidWithMeta = syn_test_suite_helper:start_process(),
  220. %% retrieve
  221. [] = syn:get_members(GroupName),
  222. [] = syn:get_members(GroupName, with_meta),
  223. false = syn:member(Pid, GroupName),
  224. false = syn:member(PidWithMeta, GroupName),
  225. %% join
  226. ok = syn:join(GroupName, Pid),
  227. ok = syn:join(GroupName, PidWithMeta, {with, meta}),
  228. %% retrieve
  229. true = syn:member(Pid, GroupName),
  230. true = syn:member(PidWithMeta, GroupName),
  231. true = lists:sort([Pid, PidWithMeta]) =:= lists:sort(syn:get_members(GroupName)),
  232. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with, meta}}])
  233. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  234. %% leave
  235. ok = syn:leave(GroupName, Pid),
  236. ok = syn:leave(GroupName, PidWithMeta),
  237. timer:sleep(100),
  238. %% retrieve
  239. [] = syn:get_members(GroupName),
  240. [] = syn:get_members(GroupName, with_meta),
  241. false = syn:member(Pid, GroupName),
  242. false = syn:member(PidWithMeta, GroupName),
  243. %% kill processes
  244. syn_test_suite_helper:kill_process(Pid),
  245. syn_test_suite_helper:kill_process(PidWithMeta).
  246. single_node_join_errors(_Config) ->
  247. GroupName = "my group",
  248. %% start
  249. ok = syn:start(),
  250. %% start processes
  251. Pid = syn_test_suite_helper:start_process(),
  252. Pid2 = syn_test_suite_helper:start_process(),
  253. %% join
  254. ok = syn:join(GroupName, Pid),
  255. ok = syn:join(GroupName, Pid2),
  256. true = syn:member(Pid, GroupName),
  257. true = syn:member(Pid2, GroupName),
  258. %% leave
  259. ok = syn:leave(GroupName, Pid),
  260. {error, not_in_group} = syn:leave(GroupName, Pid),
  261. %% kill
  262. syn_test_suite_helper:kill_process(Pid2),
  263. timer:sleep(200),
  264. {error, not_in_group} = syn:leave(GroupName, Pid2),
  265. {error, not_alive} = syn:join(GroupName, Pid2),
  266. %% kill processes
  267. syn_test_suite_helper:kill_process(Pid).
  268. single_node_publish(_Config) ->
  269. GroupName = "my group",
  270. Message = {test, message},
  271. %% start
  272. ok = syn:start(),
  273. %% start processes
  274. ResultPid = self(),
  275. F = fun() ->
  276. receive
  277. Message -> ResultPid ! {received, self(), Message}
  278. end
  279. end,
  280. Pid = syn_test_suite_helper:start_process(F),
  281. Pid2 = syn_test_suite_helper:start_process(F),
  282. OtherPid = syn_test_suite_helper:start_process(F),
  283. %% join
  284. ok = syn:join(GroupName, Pid),
  285. ok = syn:join(GroupName, Pid2),
  286. true = syn:member(Pid, GroupName),
  287. true = syn:member(Pid2, GroupName),
  288. %% send
  289. {ok, 2} = syn:publish(GroupName, Message),
  290. %% check
  291. receive
  292. {received, Pid, Message} -> ok
  293. after 2000 ->
  294. ok = published_message_was_not_received_by_pid_1
  295. end,
  296. receive
  297. {received, Pid2, Message} -> ok
  298. after 2000 ->
  299. ok = published_message_was_not_received_by_pid_2
  300. end,
  301. %% kill processes
  302. syn_test_suite_helper:kill_process(Pid),
  303. syn_test_suite_helper:kill_process(Pid2).
  304. two_nodes_join_monitor_and_unregister(Config) ->
  305. GroupName = "my group",
  306. %% get slave
  307. SlaveNode = proplists:get_value(slave_node, Config),
  308. %% start
  309. ok = syn:start(),
  310. ok = rpc:call(SlaveNode, syn, start, []),
  311. timer:sleep(100),
  312. %% start processes
  313. LocalPid = syn_test_suite_helper:start_process(),
  314. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  315. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  316. OtherPid = syn_test_suite_helper:start_process(),
  317. %% retrieve
  318. [] = syn:get_members("group-1"),
  319. [] = syn:get_members(GroupName),
  320. [] = syn:get_members(GroupName, with_meta),
  321. false = syn:member(LocalPid, GroupName),
  322. false = syn:member(RemotePid, GroupName),
  323. false = syn:member(RemotePidJoinRemote, GroupName),
  324. false = syn:member(OtherPid, GroupName),
  325. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  326. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  327. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  328. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  329. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  330. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  331. %% join
  332. ok = syn:join(GroupName, LocalPid),
  333. ok = syn:join(GroupName, RemotePid, {with_meta}),
  334. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  335. ok = syn:join("other-group", OtherPid),
  336. timer:sleep(200),
  337. %% retrieve local
  338. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote]) =:= lists:sort(syn:get_members(GroupName)),
  339. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  340. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  341. true = syn:member(LocalPid, GroupName),
  342. true = syn:member(RemotePid, GroupName),
  343. true = syn:member(RemotePidJoinRemote, GroupName),
  344. false = syn:member(OtherPid, GroupName),
  345. %% retrieve remote
  346. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote])
  347. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName])),
  348. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  349. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta])),
  350. true = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  351. true = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  352. true = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  353. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  354. %% leave & kill
  355. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  356. ok = syn:leave(GroupName, RemotePid),
  357. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  358. syn_test_suite_helper:kill_process(OtherPid),
  359. timer:sleep(200),
  360. %% retrieve
  361. [] = syn:get_members("group-1"),
  362. [] = syn:get_members(GroupName),
  363. [] = syn:get_members(GroupName, with_meta),
  364. false = syn:member(LocalPid, GroupName),
  365. false = syn:member(RemotePid, GroupName),
  366. false = syn:member(RemotePidJoinRemote, GroupName),
  367. false = syn:member(OtherPid, GroupName),
  368. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  369. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  370. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  371. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  372. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  373. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  374. %% kill processes
  375. syn_test_suite_helper:kill_process(LocalPid),
  376. syn_test_suite_helper:kill_process(RemotePid).
  377. two_nodes_local_members(Config) ->
  378. GroupName = "my group",
  379. %% get slave
  380. SlaveNode = proplists:get_value(slave_node, Config),
  381. %% start
  382. ok = syn:start(),
  383. ok = rpc:call(SlaveNode, syn, start, []),
  384. timer:sleep(100),
  385. %% start processes
  386. LocalPid = syn_test_suite_helper:start_process(),
  387. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  388. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  389. OtherPid = syn_test_suite_helper:start_process(),
  390. %% local members
  391. [] = syn:get_local_members(GroupName),
  392. [] = syn:get_local_members(GroupName, with_meta),
  393. false = syn:local_member(LocalPid, GroupName),
  394. false = syn:local_member(RemotePid, GroupName),
  395. false = syn:local_member(RemotePidJoinRemote, GroupName),
  396. false = syn:local_member(OtherPid, GroupName),
  397. %% remote members
  398. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  399. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]),
  400. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  401. false = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  402. false = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  403. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  404. %% join
  405. ok = syn:join(GroupName, LocalPid),
  406. ok = syn:join(GroupName, RemotePid, {meta, 2}),
  407. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  408. ok = syn:join({"other-group"}, OtherPid),
  409. timer:sleep(200),
  410. %% local members
  411. [LocalPid] = syn:get_local_members(GroupName),
  412. [{LocalPid, undefined}] = syn:get_local_members(GroupName, with_meta),
  413. [OtherPid] = syn:get_local_members({"other-group"}),
  414. true = syn:local_member(LocalPid, GroupName),
  415. false = syn:local_member(RemotePid, GroupName),
  416. false = syn:local_member(RemotePidJoinRemote, GroupName),
  417. false = syn:local_member(OtherPid, GroupName),
  418. true = syn:local_member(OtherPid, {"other-group"}),
  419. %% remote members
  420. true = lists:sort([RemotePid, RemotePidJoinRemote])
  421. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName])),
  422. true = lists:sort([{RemotePid, {meta, 2}}, {RemotePidJoinRemote, undefined}])
  423. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta])),
  424. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  425. true = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  426. true = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  427. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  428. %% leave & kill
  429. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  430. ok = syn:leave(GroupName, RemotePid),
  431. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  432. syn_test_suite_helper:kill_process(OtherPid),
  433. timer:sleep(200),
  434. %% local members
  435. [] = syn:get_local_members(GroupName),
  436. [] = syn:get_local_members(GroupName, with_meta),
  437. %% remote members
  438. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  439. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]),
  440. %% kill processes
  441. syn_test_suite_helper:kill_process(LocalPid),
  442. syn_test_suite_helper:kill_process(RemotePid).
  443. two_nodes_publish(Config) ->
  444. GroupName = "my group",
  445. Message = {test, message},
  446. %% get slave
  447. SlaveNode = proplists:get_value(slave_node, Config),
  448. %% start
  449. ok = syn:start(),
  450. ok = rpc:call(SlaveNode, syn, start, []),
  451. timer:sleep(100),
  452. %% start processes
  453. ResultPid = self(),
  454. F = fun() ->
  455. receive
  456. Message -> ResultPid ! {received, self(), Message}
  457. end
  458. end,
  459. LocalPid = syn_test_suite_helper:start_process(F),
  460. LocalPid2 = syn_test_suite_helper:start_process(F),
  461. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  462. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  463. OtherPid = syn_test_suite_helper:start_process(F),
  464. %% join
  465. ok = syn:join(GroupName, LocalPid),
  466. ok = syn:join(GroupName, LocalPid2),
  467. ok = syn:join(GroupName, RemotePid),
  468. ok = syn:join(GroupName, RemotePid2),
  469. timer:sleep(200),
  470. %% send
  471. {ok, 4} = syn:publish(GroupName, Message),
  472. %% check
  473. receive
  474. {received, LocalPid, Message} -> ok
  475. after 2000 ->
  476. ok = published_message_was_not_received_by_local_pid_1
  477. end,
  478. receive
  479. {received, LocalPid2, Message} -> ok
  480. after 2000 ->
  481. ok = published_message_was_not_received_by_local_pid_2
  482. end,
  483. receive
  484. {received, RemotePid, Message} -> ok
  485. after 2000 ->
  486. ok = published_message_was_not_received_by_remote_pid_2
  487. end,
  488. receive
  489. {received, RemotePid2, Message} -> ok
  490. after 2000 ->
  491. ok = published_message_was_not_received_by_remote_pid_2
  492. end,
  493. %% kill processes
  494. syn_test_suite_helper:kill_process(LocalPid),
  495. syn_test_suite_helper:kill_process(LocalPid2),
  496. syn_test_suite_helper:kill_process(RemotePid),
  497. syn_test_suite_helper:kill_process(RemotePid2).
  498. three_nodes_partial_netsplit_consistency(Config) ->
  499. GroupName = "my group",
  500. %% get slaves
  501. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  502. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  503. %% start syn on nodes
  504. ok = syn:start(),
  505. ok = rpc:call(SlaveNode1, syn, start, []),
  506. ok = rpc:call(SlaveNode2, syn, start, []),
  507. timer:sleep(100),
  508. %% start processes
  509. Pid0 = syn_test_suite_helper:start_process(),
  510. Pid0Changed = syn_test_suite_helper:start_process(),
  511. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  512. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  513. OtherPid = syn_test_suite_helper:start_process(),
  514. timer:sleep(100),
  515. %% retrieve local
  516. [] = syn:get_members("group-1"),
  517. [] = syn:get_members(GroupName),
  518. [] = syn:get_members(GroupName, with_meta),
  519. false = syn:member(Pid0, GroupName),
  520. false = syn:member(Pid0Changed, GroupName),
  521. false = syn:member(Pid1, GroupName),
  522. false = syn:member(Pid2, GroupName),
  523. %% retrieve slave 1
  524. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  525. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  526. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  527. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  528. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  529. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  530. %% retrieve slave 2
  531. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  532. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  533. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  534. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  535. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  536. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  537. %% join
  538. ok = syn:join(GroupName, Pid0),
  539. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  540. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  541. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  542. ok = syn:join("other-group", OtherPid),
  543. timer:sleep(200),
  544. %% retrieve local
  545. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  546. true = lists:sort([
  547. {Pid0, undefined},
  548. {Pid0Changed, {meta, changed}},
  549. {Pid1, undefined},
  550. {Pid2, {meta, 2}}
  551. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  552. true = syn:member(Pid0, GroupName),
  553. true = syn:member(Pid0Changed, GroupName),
  554. true = syn:member(Pid1, GroupName),
  555. true = syn:member(Pid2, GroupName),
  556. false = syn:member(OtherPid, GroupName),
  557. %% retrieve slave 1
  558. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  559. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  560. true = lists:sort([
  561. {Pid0, undefined},
  562. {Pid0Changed, {meta, changed}},
  563. {Pid1, undefined},
  564. {Pid2, {meta, 2}}
  565. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  566. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  567. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  568. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  569. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  570. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  571. %% retrieve slave 2
  572. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  573. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  574. true = lists:sort([
  575. {Pid0, undefined},
  576. {Pid0Changed, {meta, changed}},
  577. {Pid1, undefined},
  578. {Pid2, {meta, 2}}
  579. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  580. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  581. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  582. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  583. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  584. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  585. %% disconnect slave 2 from main (slave 1 can still see slave 2)
  586. syn_test_suite_helper:disconnect_node(SlaveNode2),
  587. timer:sleep(500),
  588. %% retrieve local
  589. true = lists:sort([Pid0, Pid0Changed, Pid1]) =:= lists:sort(syn:get_members(GroupName)),
  590. true = lists:sort([
  591. {Pid0, undefined},
  592. {Pid0Changed, {meta, changed}},
  593. {Pid1, undefined}
  594. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  595. true = syn:member(Pid0, GroupName),
  596. true = syn:member(Pid0Changed, GroupName),
  597. true = syn:member(Pid1, GroupName),
  598. false = syn:member(Pid2, GroupName),
  599. false = syn:member(OtherPid, GroupName),
  600. %% retrieve slave 1
  601. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  602. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  603. true = lists:sort([
  604. {Pid0, undefined},
  605. {Pid0Changed, {meta, changed}},
  606. {Pid1, undefined},
  607. {Pid2, {meta, 2}}
  608. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  609. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  610. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  611. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  612. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  613. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  614. %% disconnect slave 1
  615. syn_test_suite_helper:disconnect_node(SlaveNode1),
  616. timer:sleep(500),
  617. %% leave 0Changed
  618. ok = syn:leave(GroupName, Pid0Changed),
  619. %% retrieve local
  620. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  621. true = lists:sort([
  622. {Pid0, undefined}
  623. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  624. true = syn:member(Pid0, GroupName),
  625. false = syn:member(Pid0Changed, GroupName),
  626. false = syn:member(Pid1, GroupName),
  627. false = syn:member(Pid2, GroupName),
  628. false = syn:member(OtherPid, GroupName),
  629. %% reconnect all
  630. syn_test_suite_helper:connect_node(SlaveNode1),
  631. syn_test_suite_helper:connect_node(SlaveNode2),
  632. timer:sleep(5000),
  633. %% retrieve local
  634. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  635. true = lists:sort([
  636. {Pid0, undefined},
  637. {Pid1, undefined},
  638. {Pid2, {meta, 2}}
  639. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  640. true = syn:member(Pid0, GroupName),
  641. false = syn:member(Pid0Changed, GroupName),
  642. true = syn:member(Pid1, GroupName),
  643. true = syn:member(Pid2, GroupName),
  644. false = syn:member(OtherPid, GroupName),
  645. %% retrieve slave 1
  646. true = lists:sort([Pid0, Pid1, Pid2])
  647. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  648. true = lists:sort([
  649. {Pid0, undefined},
  650. {Pid1, undefined},
  651. {Pid2, {meta, 2}}
  652. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  653. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  654. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  655. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  656. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  657. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  658. %% retrieve slave 2
  659. true = lists:sort([Pid0, Pid1, Pid2])
  660. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  661. true = lists:sort([
  662. {Pid0, undefined},
  663. {Pid1, undefined},
  664. {Pid2, {meta, 2}}
  665. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  666. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  667. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  668. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  669. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  670. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  671. %% kill processes
  672. syn_test_suite_helper:kill_process(Pid0),
  673. syn_test_suite_helper:kill_process(Pid0Changed),
  674. syn_test_suite_helper:kill_process(Pid1),
  675. syn_test_suite_helper:kill_process(Pid2).
  676. three_nodes_full_netsplit_consistency(Config) ->
  677. GroupName = "my group",
  678. %% get slaves
  679. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  680. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  681. %% start syn on nodes
  682. ok = syn:start(),
  683. ok = rpc:call(SlaveNode1, syn, start, []),
  684. ok = rpc:call(SlaveNode2, syn, start, []),
  685. timer:sleep(100),
  686. %% start processes
  687. Pid0 = syn_test_suite_helper:start_process(),
  688. Pid0Changed = syn_test_suite_helper:start_process(),
  689. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  690. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  691. OtherPid = syn_test_suite_helper:start_process(),
  692. timer:sleep(100),
  693. %% retrieve local
  694. [] = syn:get_members("group-1"),
  695. [] = syn:get_members(GroupName),
  696. [] = syn:get_members(GroupName, with_meta),
  697. false = syn:member(Pid0, GroupName),
  698. false = syn:member(Pid0Changed, GroupName),
  699. false = syn:member(Pid1, GroupName),
  700. false = syn:member(Pid2, GroupName),
  701. %% retrieve slave 1
  702. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  703. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  704. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  705. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  706. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  707. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  708. %% retrieve slave 2
  709. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  710. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  711. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  712. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  713. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  714. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  715. %% join
  716. ok = syn:join(GroupName, Pid0),
  717. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  718. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  719. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  720. ok = syn:join("other-group", OtherPid),
  721. timer:sleep(200),
  722. %% retrieve local
  723. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  724. true = lists:sort([
  725. {Pid0, undefined},
  726. {Pid0Changed, {meta, changed}},
  727. {Pid1, undefined},
  728. {Pid2, {meta, 2}}
  729. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  730. true = syn:member(Pid0, GroupName),
  731. true = syn:member(Pid0Changed, GroupName),
  732. true = syn:member(Pid1, GroupName),
  733. true = syn:member(Pid2, GroupName),
  734. false = syn:member(OtherPid, GroupName),
  735. %% retrieve slave 1
  736. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  737. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  738. true = lists:sort([
  739. {Pid0, undefined},
  740. {Pid0Changed, {meta, changed}},
  741. {Pid1, undefined},
  742. {Pid2, {meta, 2}}
  743. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  744. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  745. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  746. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  747. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  748. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  749. %% retrieve slave 2
  750. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  751. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  752. true = lists:sort([
  753. {Pid0, undefined},
  754. {Pid0Changed, {meta, changed}},
  755. {Pid1, undefined},
  756. {Pid2, {meta, 2}}
  757. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  758. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  759. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  760. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  761. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  762. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  763. %% disconnect everyone
  764. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  765. syn_test_suite_helper:disconnect_node(SlaveNode1),
  766. syn_test_suite_helper:disconnect_node(SlaveNode2),
  767. timer:sleep(1000),
  768. %% leave 0Changed
  769. ok = syn:leave(GroupName, Pid0Changed),
  770. %% retrieve local
  771. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  772. true = lists:sort([
  773. {Pid0, undefined}
  774. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  775. true = syn:member(Pid0, GroupName),
  776. false = syn:member(Pid0Changed, GroupName),
  777. false = syn:member(Pid1, GroupName),
  778. false = syn:member(Pid2, GroupName),
  779. false = syn:member(OtherPid, GroupName),
  780. %% reconnect all
  781. syn_test_suite_helper:connect_node(SlaveNode1),
  782. syn_test_suite_helper:connect_node(SlaveNode2),
  783. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  784. timer:sleep(1500),
  785. %% retrieve local
  786. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  787. true = lists:sort([
  788. {Pid0, undefined},
  789. {Pid1, undefined},
  790. {Pid2, {meta, 2}}
  791. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  792. true = syn:member(Pid0, GroupName),
  793. false = syn:member(Pid0Changed, GroupName),
  794. true = syn:member(Pid1, GroupName),
  795. true = syn:member(Pid2, GroupName),
  796. false = syn:member(OtherPid, GroupName),
  797. %% retrieve slave 1
  798. true = lists:sort([Pid0, Pid1, Pid2])
  799. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  800. true = lists:sort([
  801. {Pid0, undefined},
  802. {Pid1, undefined},
  803. {Pid2, {meta, 2}}
  804. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  805. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  806. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  807. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  808. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  809. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  810. %% retrieve slave 2
  811. true = lists:sort([Pid0, Pid1, Pid2])
  812. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  813. true = lists:sort([
  814. {Pid0, undefined},
  815. {Pid1, undefined},
  816. {Pid2, {meta, 2}}
  817. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  818. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  819. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  820. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  821. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  822. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  823. %% kill processes
  824. syn_test_suite_helper:kill_process(Pid0),
  825. syn_test_suite_helper:kill_process(Pid0Changed),
  826. syn_test_suite_helper:kill_process(Pid1),
  827. syn_test_suite_helper:kill_process(Pid2).