syn_groups_SUITE.erl 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. %% ==========================================================================================================
  2. %% Syn - A global Process Registry and Process Group manager.
  3. %%
  4. %% The MIT License (MIT)
  5. %%
  6. %% Copyright (c) 2015-2021 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. three_nodes_discover_default_scope/1,
  35. three_nodes_discover_custom_scope/1,
  36. three_nodes_join_leave_and_monitor_default_scope/1,
  37. three_nodes_join_leave_and_monitor_custom_scope/1,
  38. three_nodes_cluster_changes/1,
  39. three_nodes_custom_event_handler_joined_left/1
  40. ]).
  41. %% include
  42. -include_lib("common_test/include/ct.hrl").
  43. -include_lib("syn/src/syn.hrl").
  44. %% ===================================================================
  45. %% Callbacks
  46. %% ===================================================================
  47. %% -------------------------------------------------------------------
  48. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  49. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  50. %% GroupName = atom()
  51. %% TestCase = atom()
  52. %% Reason = any()
  53. %% -------------------------------------------------------------------
  54. all() ->
  55. [
  56. {group, three_nodes_groups}
  57. ].
  58. %% -------------------------------------------------------------------
  59. %% Function: groups() -> [Group]
  60. %% Group = {GroupName,Properties,GroupsAndTestCases}
  61. %% GroupName = atom()
  62. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  63. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  64. %% TestCase = atom()
  65. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  66. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  67. %% repeat_until_any_ok | repeat_until_any_fail
  68. %% N = integer() | forever
  69. %% -------------------------------------------------------------------
  70. groups() ->
  71. [
  72. {three_nodes_groups, [shuffle], [
  73. three_nodes_discover_default_scope,
  74. three_nodes_discover_custom_scope,
  75. three_nodes_join_leave_and_monitor_default_scope,
  76. three_nodes_join_leave_and_monitor_custom_scope,
  77. three_nodes_cluster_changes,
  78. three_nodes_custom_event_handler_joined_left
  79. ]}
  80. ].
  81. %% -------------------------------------------------------------------
  82. %% Function: init_per_suite(Config0) ->
  83. %% Config1 | {skip,Reason} |
  84. %% {skip_and_save,Reason,Config1}
  85. %% Config0 = Config1 = [tuple()]
  86. %% Reason = any()
  87. %% -------------------------------------------------------------------
  88. init_per_suite(Config) ->
  89. Config.
  90. %% -------------------------------------------------------------------
  91. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  92. %% Config0 = Config1 = [tuple()]
  93. %% -------------------------------------------------------------------
  94. end_per_suite(_Config) ->
  95. ok.
  96. %% -------------------------------------------------------------------
  97. %% Function: init_per_group(GroupName, Config0) ->
  98. %% Config1 | {skip,Reason} |
  99. %% {skip_and_save,Reason,Config1}
  100. %% GroupName = atom()
  101. %% Config0 = Config1 = [tuple()]
  102. %% Reason = any()
  103. %% -------------------------------------------------------------------
  104. init_per_group(three_nodes_groups, Config) ->
  105. %% start slave
  106. {ok, SlaveNode1} = syn_test_suite_helper:start_slave(syn_slave_1),
  107. {ok, SlaveNode2} = syn_test_suite_helper:start_slave(syn_slave_2),
  108. syn_test_suite_helper:connect_node(SlaveNode1),
  109. syn_test_suite_helper:connect_node(SlaveNode2),
  110. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  111. %% wait full cluster
  112. case syn_test_suite_helper:wait_cluster_mesh_connected([node(), SlaveNode1, SlaveNode2]) of
  113. ok ->
  114. %% config
  115. [{slave_node_1, SlaveNode1}, {slave_node_2, SlaveNode2} | Config];
  116. Other ->
  117. ct:pal("*********** Could not get full cluster, skipping"),
  118. end_per_group(three_nodes_groups, Config),
  119. {skip, Other}
  120. end;
  121. init_per_group(_GroupName, Config) ->
  122. Config.
  123. %% -------------------------------------------------------------------
  124. %% Function: end_per_group(GroupName, Config0) ->
  125. %% void() | {save_config,Config1}
  126. %% GroupName = atom()
  127. %% Config0 = Config1 = [tuple()]
  128. %% -------------------------------------------------------------------
  129. end_per_group(three_nodes_groups, Config) ->
  130. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  131. syn_test_suite_helper:connect_node(SlaveNode1),
  132. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  133. syn_test_suite_helper:connect_node(SlaveNode2),
  134. syn_test_suite_helper:clean_after_test(),
  135. syn_test_suite_helper:stop_slave(syn_slave_1),
  136. syn_test_suite_helper:stop_slave(syn_slave_2),
  137. timer:sleep(1000);
  138. end_per_group(_GroupName, _Config) ->
  139. syn_test_suite_helper:clean_after_test().
  140. %% -------------------------------------------------------------------
  141. %% Function: init_per_testcase(TestCase, Config0) ->
  142. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  143. %% TestCase = atom()
  144. %% Config0 = Config1 = [tuple()]
  145. %% Reason = any()
  146. %% -------------------------------------------------------------------
  147. init_per_testcase(TestCase, Config) ->
  148. ct:pal("Starting test: ~p", [TestCase]),
  149. Config.
  150. %% -------------------------------------------------------------------
  151. %% Function: end_per_testcase(TestCase, Config0) ->
  152. %% void() | {save_config,Config1} | {fail,Reason}
  153. %% TestCase = atom()
  154. %% Config0 = Config1 = [tuple()]
  155. %% Reason = any()
  156. %% -------------------------------------------------------------------
  157. end_per_testcase(_, _Config) ->
  158. syn_test_suite_helper:clean_after_test().
  159. %% ===================================================================
  160. %% Tests
  161. %% ===================================================================
  162. three_nodes_discover_default_scope(Config) ->
  163. %% get slaves
  164. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  165. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  166. %% start syn on nodes
  167. ok = syn:start(),
  168. ok = rpc:call(SlaveNode1, syn, start, []),
  169. ok = rpc:call(SlaveNode2, syn, start, []),
  170. %% check
  171. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  172. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  173. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  174. %% simulate full netsplit
  175. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  176. syn_test_suite_helper:disconnect_node(SlaveNode1),
  177. syn_test_suite_helper:disconnect_node(SlaveNode2),
  178. syn_test_suite_helper:assert_cluster(node(), []),
  179. %% check
  180. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, []),
  181. %% reconnect slave 1
  182. syn_test_suite_helper:connect_node(SlaveNode1),
  183. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1]),
  184. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  185. %% check
  186. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1]),
  187. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node()]),
  188. %% reconnect all
  189. syn_test_suite_helper:connect_node(SlaveNode2),
  190. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  191. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  192. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  193. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  194. %% check
  195. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  196. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  197. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  198. %% simulate full netsplit, again
  199. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  200. syn_test_suite_helper:disconnect_node(SlaveNode1),
  201. syn_test_suite_helper:disconnect_node(SlaveNode2),
  202. syn_test_suite_helper:assert_cluster(node(), []),
  203. %% check
  204. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, []),
  205. %% reconnect all, again
  206. syn_test_suite_helper:connect_node(SlaveNode2),
  207. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  208. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  209. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  210. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  211. %% check
  212. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  213. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  214. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  215. %% crash the scope process on local
  216. syn_test_suite_helper:kill_process(syn_registry_default),
  217. syn_test_suite_helper:wait_process_name_ready(syn_registry_default),
  218. %% check, it should have rebuilt after supervisor restarts it
  219. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  220. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  221. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  222. %% crash scopes supervisor on local
  223. syn_test_suite_helper:kill_process(syn_scopes_sup),
  224. syn_test_suite_helper:wait_process_name_ready(syn_registry_default),
  225. %% check
  226. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  227. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  228. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]).
  229. three_nodes_discover_custom_scope(Config) ->
  230. %% get slaves
  231. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  232. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  233. %% start syn on nodes
  234. ok = syn:start(),
  235. ok = rpc:call(SlaveNode1, syn, start, []),
  236. ok = rpc:call(SlaveNode2, syn, start, []),
  237. %% add custom scopes
  238. ok = syn:add_node_to_scope(custom_scope_ab),
  239. ok = syn:add_node_to_scope(custom_scope_all),
  240. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc, custom_scope_all]]),
  241. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc, custom_scope_c, custom_scope_all]]),
  242. %% get_subcluster_nodes should return invalid errors
  243. {'EXIT', {{invalid_scope, custom_abcdef}, _}} = catch syn_registry:get_subcluster_nodes(custom_abcdef),
  244. %% check
  245. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  246. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  247. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  248. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  249. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  250. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  251. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  252. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]),
  253. %% check default
  254. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  255. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  256. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  257. %% disconnect node 2 (node 1 can still see node 2)
  258. syn_test_suite_helper:disconnect_node(SlaveNode2),
  259. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1]),
  260. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  261. %% check
  262. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  263. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1]),
  264. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  265. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  266. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  267. %% reconnect node 2
  268. syn_test_suite_helper:connect_node(SlaveNode2),
  269. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  270. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  271. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  272. %% check
  273. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  274. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  275. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  276. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  277. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  278. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  279. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  280. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]),
  281. %% crash a scope process on 2
  282. rpc:call(SlaveNode2, syn_test_suite_helper, kill_process, [syn_registry_custom_scope_bc]),
  283. rpc:call(SlaveNode2, syn_test_suite_helper, wait_process_name_ready, [syn_registry_default]),
  284. %% check
  285. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  286. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  287. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  288. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  289. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  290. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  291. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  292. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]),
  293. %% crash scopes supervisor on local
  294. syn_test_suite_helper:kill_process(syn_scopes_sup),
  295. syn_test_suite_helper:wait_process_name_ready(syn_registry_default),
  296. %% check
  297. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  298. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  299. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  300. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  301. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  302. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  303. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  304. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]).
  305. three_nodes_join_leave_and_monitor_default_scope(Config) ->
  306. %% get slaves
  307. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  308. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  309. %% start syn on nodes
  310. ok = syn:start(),
  311. ok = rpc:call(SlaveNode1, syn, start, []),
  312. ok = rpc:call(SlaveNode2, syn, start, []),
  313. %% start processes
  314. Pid = syn_test_suite_helper:start_process(),
  315. PidWithMeta = syn_test_suite_helper:start_process(),
  316. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  317. %% check
  318. [] = syn:get_members({group, "one"}),
  319. [] = rpc:call(SlaveNode1, syn, get_members, [{group, "one"}]),
  320. [] = rpc:call(SlaveNode2, syn, get_members, [{group, "one"}]),
  321. [] = syn:get_members({group, "two"}),
  322. [] = rpc:call(SlaveNode1, syn, get_members, [{group, "two"}]),
  323. [] = rpc:call(SlaveNode2, syn, get_members, [{group, "two"}]),
  324. [] = syn:get_local_members({group, "one"}),
  325. [] = rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}]),
  326. [] = rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}]),
  327. [] = syn:get_local_members({group, "two"}),
  328. [] = rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}]),
  329. [] = rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}]),
  330. 0 = syn:groups_count(default),
  331. 0 = syn:groups_count(default, node()),
  332. 0 = syn:groups_count(default, SlaveNode1),
  333. 0 = syn:groups_count(default, SlaveNode2),
  334. %% join
  335. ok = syn:join({group, "one"}, Pid),
  336. ok = syn:join({group, "one"}, PidWithMeta, <<"with meta">>),
  337. ok = syn:join({group, "one"}, PidRemoteOn1),
  338. ok = syn:join({group, "two"}, Pid),
  339. ok = syn:join({group, "two"}, PidWithMeta, "with-meta-2"),
  340. %% errors
  341. {error, not_alive} = syn:join({"pid not alive"}, list_to_pid("<0.9999.0>")),
  342. {error, not_in_group} = syn:leave({group, "three"}, Pid),
  343. %% retrieve
  344. syn_test_suite_helper:assert_wait(
  345. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  346. fun() -> lists:sort(syn:get_members({group, "one"})) end
  347. ),
  348. syn_test_suite_helper:assert_wait(
  349. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  350. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "one"}])) end
  351. ),
  352. syn_test_suite_helper:assert_wait(
  353. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  354. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "one"}])) end
  355. ),
  356. syn_test_suite_helper:assert_wait(
  357. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  358. fun() -> lists:sort(syn:get_local_members({group, "one"})) end
  359. ),
  360. syn_test_suite_helper:assert_wait(
  361. [{PidRemoteOn1, undefined}],
  362. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}])) end
  363. ),
  364. syn_test_suite_helper:assert_wait(
  365. [],
  366. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}])) end
  367. ),
  368. syn_test_suite_helper:assert_wait(
  369. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  370. fun() -> lists:sort(syn:get_members({group, "two"})) end
  371. ),
  372. syn_test_suite_helper:assert_wait(
  373. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  374. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "two"}])) end
  375. ),
  376. syn_test_suite_helper:assert_wait(
  377. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  378. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "two"}])) end
  379. ),
  380. syn_test_suite_helper:assert_wait(
  381. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  382. fun() -> lists:sort(syn:get_local_members({group, "two"})) end
  383. ),
  384. syn_test_suite_helper:assert_wait(
  385. [],
  386. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}])) end
  387. ),
  388. syn_test_suite_helper:assert_wait(
  389. [],
  390. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}])) end
  391. ),
  392. 2 = syn:groups_count(default),
  393. 2 = syn:groups_count(default, node()),
  394. 1 = syn:groups_count(default, SlaveNode1),
  395. 0 = syn:groups_count(default, SlaveNode2),
  396. %% re-join to edit meta
  397. ok = syn:join({group, "one"}, PidWithMeta, <<"with updated meta">>),
  398. ok = rpc:call(SlaveNode2, syn, join, [{group, "one"}, PidRemoteOn1, added_meta]), %% updated on slave 2
  399. %% retrieve
  400. syn_test_suite_helper:assert_wait(
  401. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  402. fun() -> lists:sort(syn:get_members({group, "one"})) end
  403. ),
  404. syn_test_suite_helper:assert_wait(
  405. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  406. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "one"}])) end
  407. ),
  408. syn_test_suite_helper:assert_wait(
  409. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  410. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "one"}])) end
  411. ),
  412. syn_test_suite_helper:assert_wait(
  413. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  414. fun() -> lists:sort(syn:get_local_members({group, "one"})) end
  415. ),
  416. syn_test_suite_helper:assert_wait(
  417. [{PidRemoteOn1, added_meta}],
  418. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}])) end
  419. ),
  420. syn_test_suite_helper:assert_wait(
  421. [],
  422. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}])) end
  423. ),
  424. syn_test_suite_helper:assert_wait(
  425. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  426. fun() -> lists:sort(syn:get_members({group, "two"})) end
  427. ),
  428. syn_test_suite_helper:assert_wait(
  429. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  430. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "two"}])) end
  431. ),
  432. syn_test_suite_helper:assert_wait(
  433. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  434. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "two"}])) end
  435. ),
  436. syn_test_suite_helper:assert_wait(
  437. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  438. fun() -> lists:sort(syn:get_local_members({group, "two"})) end
  439. ),
  440. syn_test_suite_helper:assert_wait(
  441. [],
  442. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}])) end
  443. ),
  444. syn_test_suite_helper:assert_wait(
  445. [],
  446. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}])) end
  447. ),
  448. 2 = syn:groups_count(default),
  449. 2 = syn:groups_count(default, node()),
  450. 1 = syn:groups_count(default, SlaveNode1),
  451. 0 = syn:groups_count(default, SlaveNode2),
  452. %% crash scope process to ensure that monitors get recreated
  453. exit(whereis(syn_groups_default), kill),
  454. syn_test_suite_helper:wait_process_name_ready(syn_groups_default),
  455. %% kill process
  456. syn_test_suite_helper:kill_process(Pid),
  457. syn_test_suite_helper:kill_process(PidRemoteOn1),
  458. %% leave
  459. ok = syn:leave({group, "one"}, PidWithMeta),
  460. %% retrieve
  461. syn_test_suite_helper:assert_wait(
  462. [],
  463. fun() -> lists:sort(syn:get_members({group, "one"})) end
  464. ),
  465. syn_test_suite_helper:assert_wait(
  466. [],
  467. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "one"}])) end
  468. ),
  469. syn_test_suite_helper:assert_wait(
  470. [],
  471. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "one"}])) end
  472. ),
  473. syn_test_suite_helper:assert_wait(
  474. [],
  475. fun() -> lists:sort(syn:get_local_members({group, "one"})) end
  476. ),
  477. syn_test_suite_helper:assert_wait(
  478. [],
  479. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}])) end
  480. ),
  481. syn_test_suite_helper:assert_wait(
  482. [],
  483. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}])) end
  484. ),
  485. syn_test_suite_helper:assert_wait(
  486. [{PidWithMeta, "with-meta-2"}],
  487. fun() -> lists:sort(syn:get_members({group, "two"})) end
  488. ),
  489. syn_test_suite_helper:assert_wait(
  490. [{PidWithMeta, "with-meta-2"}],
  491. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "two"}])) end
  492. ),
  493. syn_test_suite_helper:assert_wait(
  494. [{PidWithMeta, "with-meta-2"}],
  495. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "two"}])) end
  496. ),
  497. syn_test_suite_helper:assert_wait(
  498. [{PidWithMeta, "with-meta-2"}],
  499. fun() -> lists:sort(syn:get_local_members({group, "two"})) end
  500. ),
  501. syn_test_suite_helper:assert_wait(
  502. [],
  503. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}])) end
  504. ),
  505. syn_test_suite_helper:assert_wait(
  506. [],
  507. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}])) end
  508. ),
  509. 1 = syn:groups_count(default),
  510. 1 = syn:groups_count(default, node()),
  511. 0 = syn:groups_count(default, SlaveNode1),
  512. 0 = syn:groups_count(default, SlaveNode2),
  513. %% errors
  514. {error, not_in_group} = syn:leave({group, "one"}, PidWithMeta).
  515. three_nodes_join_leave_and_monitor_custom_scope(Config) ->
  516. %% get slaves
  517. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  518. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  519. %% start syn on nodes
  520. ok = syn:start(),
  521. ok = rpc:call(SlaveNode1, syn, start, []),
  522. ok = rpc:call(SlaveNode2, syn, start, []),
  523. %% add custom scopes
  524. ok = syn:add_node_to_scope(custom_scope_ab),
  525. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc]]),
  526. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  527. %% start processes
  528. Pid = syn_test_suite_helper:start_process(),
  529. PidWithMeta = syn_test_suite_helper:start_process(),
  530. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  531. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  532. %% check
  533. [] = syn:get_members(custom_scope_ab, {group, "one"}),
  534. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}]),
  535. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  536. [] = syn:get_local_members(custom_scope_ab, {group, "one"}),
  537. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  538. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  539. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "one"}),
  540. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "one"}]),
  541. [] = rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "one"}]),
  542. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "one"}),
  543. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "one"}]),
  544. [] = rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "one"}]),
  545. [] = syn:get_members(custom_scope_ab, {group, "two"}),
  546. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}]),
  547. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  548. [] = syn:get_local_members(custom_scope_ab, {group, "two"}),
  549. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  550. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  551. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  552. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}]),
  553. [] = rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}]),
  554. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  555. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}]),
  556. [] = rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}]),
  557. %% join
  558. ok = syn:join(custom_scope_ab, {group, "one"}, Pid),
  559. ok = syn:join(custom_scope_ab, {group, "one"}, PidWithMeta, <<"with meta">>),
  560. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, {group, "two"}, PidRemoteOn1]),
  561. ok = syn:join(custom_scope_ab, {group, "two"}, Pid),
  562. ok = syn:join(custom_scope_ab, {group, "two"}, PidWithMeta, "with-meta-2"),
  563. %% errors
  564. {error, not_alive} = syn:join({"pid not alive"}, list_to_pid("<0.9999.0>")),
  565. {error, not_in_group} = syn:leave({group, "three"}, Pid),
  566. {'EXIT', {{invalid_scope, custom_scope_ab}, _}} = catch syn:join(custom_scope_ab, {group, "one"}, PidRemoteOn2),
  567. %% retrieve
  568. syn_test_suite_helper:assert_wait(
  569. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  570. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "one"})) end
  571. ),
  572. syn_test_suite_helper:assert_wait(
  573. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  574. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}])) end
  575. ),
  576. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  577. syn_test_suite_helper:assert_wait(
  578. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  579. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "one"})) end
  580. ),
  581. syn_test_suite_helper:assert_wait(
  582. [],
  583. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}])) end
  584. ),
  585. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  586. syn_test_suite_helper:assert_wait(
  587. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  588. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "two"})) end
  589. ),
  590. syn_test_suite_helper:assert_wait(
  591. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  592. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}])) end
  593. ),
  594. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  595. syn_test_suite_helper:assert_wait(
  596. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  597. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "two"})) end
  598. ),
  599. syn_test_suite_helper:assert_wait(
  600. [],
  601. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}])) end
  602. ),
  603. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  604. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  605. syn_test_suite_helper:assert_wait(
  606. [{PidRemoteOn1, undefined}],
  607. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  608. ),
  609. syn_test_suite_helper:assert_wait(
  610. [{PidRemoteOn1, undefined}],
  611. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  612. ),
  613. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  614. syn_test_suite_helper:assert_wait(
  615. [{PidRemoteOn1, undefined}],
  616. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  617. ),
  618. syn_test_suite_helper:assert_wait(
  619. [],
  620. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  621. ),
  622. 2 = syn:groups_count(custom_scope_ab),
  623. 2 = syn:groups_count(custom_scope_ab, node()),
  624. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  625. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  626. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  627. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  628. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  629. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  630. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  631. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  632. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  633. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  634. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  635. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  636. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  637. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  638. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  639. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  640. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  641. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  642. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  643. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  644. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  645. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  646. %% re-join to edit meta
  647. ok = syn:join(custom_scope_ab, {group, "one"}, PidWithMeta, <<"with updated meta">>),
  648. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, {group, "two"}, PidRemoteOn1, added_meta]), %% updated on slave 2
  649. %% retrieve
  650. syn_test_suite_helper:assert_wait(
  651. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  652. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "one"})) end
  653. ),
  654. syn_test_suite_helper:assert_wait(
  655. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  656. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}])) end
  657. ),
  658. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  659. syn_test_suite_helper:assert_wait(
  660. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  661. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "one"})) end
  662. ),
  663. syn_test_suite_helper:assert_wait(
  664. [],
  665. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}])) end
  666. ),
  667. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  668. syn_test_suite_helper:assert_wait(
  669. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  670. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "two"})) end
  671. ),
  672. syn_test_suite_helper:assert_wait(
  673. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  674. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}])) end
  675. ),
  676. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  677. syn_test_suite_helper:assert_wait(
  678. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  679. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "two"})) end
  680. ),
  681. syn_test_suite_helper:assert_wait(
  682. [],
  683. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}])) end
  684. ),
  685. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  686. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  687. syn_test_suite_helper:assert_wait(
  688. [{PidRemoteOn1, added_meta}],
  689. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  690. ),
  691. syn_test_suite_helper:assert_wait(
  692. [{PidRemoteOn1, added_meta}],
  693. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  694. ),
  695. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  696. syn_test_suite_helper:assert_wait(
  697. [{PidRemoteOn1, added_meta}],
  698. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  699. ),
  700. syn_test_suite_helper:assert_wait(
  701. [],
  702. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  703. ),
  704. 2 = syn:groups_count(custom_scope_ab),
  705. 2 = syn:groups_count(custom_scope_ab, node()),
  706. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  707. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  708. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  709. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  710. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  711. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  712. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  713. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  714. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  715. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  716. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  717. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  718. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  719. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  720. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  721. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  722. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  723. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  724. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  725. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  726. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  727. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  728. %% crash scope process to ensure that monitors get recreated
  729. exit(whereis(syn_groups_custom_scope_ab), kill),
  730. syn_test_suite_helper:wait_process_name_ready(syn_groups_custom_scope_ab),
  731. %% kill process
  732. syn_test_suite_helper:kill_process(Pid),
  733. syn_test_suite_helper:kill_process(PidRemoteOn1),
  734. %% leave
  735. ok = syn:leave(custom_scope_ab, {group, "one"}, PidWithMeta),
  736. %% retrieve
  737. syn_test_suite_helper:assert_wait(
  738. [],
  739. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "one"})) end
  740. ),
  741. syn_test_suite_helper:assert_wait(
  742. [],
  743. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}])) end
  744. ),
  745. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  746. syn_test_suite_helper:assert_wait(
  747. [],
  748. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "one"})) end
  749. ),
  750. syn_test_suite_helper:assert_wait(
  751. [],
  752. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}])) end
  753. ),
  754. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  755. syn_test_suite_helper:assert_wait(
  756. [{PidWithMeta, "with-meta-2"}],
  757. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "two"})) end
  758. ),
  759. syn_test_suite_helper:assert_wait(
  760. [{PidWithMeta, "with-meta-2"}],
  761. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}])) end
  762. ),
  763. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  764. syn_test_suite_helper:assert_wait(
  765. [{PidWithMeta, "with-meta-2"}],
  766. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "two"})) end
  767. ),
  768. syn_test_suite_helper:assert_wait(
  769. [],
  770. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}])) end
  771. ),
  772. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  773. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  774. syn_test_suite_helper:assert_wait(
  775. [],
  776. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  777. ),
  778. syn_test_suite_helper:assert_wait(
  779. [], fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  780. ),
  781. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  782. syn_test_suite_helper:assert_wait(
  783. [],
  784. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  785. ),
  786. syn_test_suite_helper:assert_wait(
  787. [], fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  788. ),
  789. 1 = syn:groups_count(custom_scope_ab),
  790. 1 = syn:groups_count(custom_scope_ab, node()),
  791. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  792. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  793. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  794. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  795. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  796. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  797. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  798. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  799. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  800. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  801. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  802. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  803. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  804. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  805. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  806. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  807. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  808. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  809. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  810. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  811. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  812. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  813. %% errors
  814. {error, not_in_group} = syn:leave(custom_scope_ab, {group, "one"}, PidWithMeta).
  815. three_nodes_cluster_changes(Config) ->
  816. %% get slaves
  817. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  818. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  819. %% disconnect 1 from 2
  820. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  821. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  822. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  823. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  824. %% start syn on 1 and 2, nodes don't know of each other
  825. ok = rpc:call(SlaveNode1, syn, start, []),
  826. ok = rpc:call(SlaveNode2, syn, start, []),
  827. %% add custom scopes
  828. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_bc]]),
  829. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  830. %% start processes
  831. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  832. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  833. %% join
  834. ok = rpc:call(SlaveNode1, syn, join, [<<"common-group">>, PidRemoteOn1, "meta-1"]),
  835. ok = rpc:call(SlaveNode2, syn, join, [<<"common-group">>, PidRemoteOn2, "meta-2"]),
  836. ok = rpc:call(SlaveNode2, syn, join, [<<"group-2">>, PidRemoteOn2, "other-meta"]),
  837. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, <<"scoped-on-bc">>, PidRemoteOn1, "scoped-meta-1"]),
  838. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, <<"scoped-on-bc">>, PidRemoteOn2, "scoped-meta-2"]),
  839. %% form full cluster
  840. ok = syn:start(),
  841. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  842. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  843. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  844. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  845. syn_test_suite_helper:wait_process_name_ready(syn_groups_default),
  846. %% retrieve
  847. syn_test_suite_helper:assert_wait(
  848. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  849. fun() -> lists:sort(syn:get_members(<<"common-group">>)) end
  850. ),
  851. syn_test_suite_helper:assert_wait(
  852. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  853. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"common-group">>])) end
  854. ),
  855. syn_test_suite_helper:assert_wait(
  856. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  857. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"common-group">>])) end
  858. ),
  859. syn_test_suite_helper:assert_wait(
  860. [],
  861. fun() -> lists:sort(syn:get_local_members(<<"common-group">>)) end
  862. ),
  863. syn_test_suite_helper:assert_wait(
  864. [{PidRemoteOn1, "meta-1"}],
  865. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"common-group">>])) end
  866. ),
  867. syn_test_suite_helper:assert_wait(
  868. [{PidRemoteOn2, "meta-2"}],
  869. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"common-group">>])) end
  870. ),
  871. syn_test_suite_helper:assert_wait(
  872. [{PidRemoteOn2, "other-meta"}],
  873. fun() -> lists:sort(syn:get_members(<<"group-2">>)) end
  874. ),
  875. syn_test_suite_helper:assert_wait(
  876. [{PidRemoteOn2, "other-meta"}],
  877. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"group-2">>])) end
  878. ),
  879. syn_test_suite_helper:assert_wait(
  880. [{PidRemoteOn2, "other-meta"}],
  881. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"group-2">>])) end
  882. ),
  883. syn_test_suite_helper:assert_wait(
  884. [],
  885. fun() -> lists:sort(syn:get_local_members(<<"group-2">>)) end
  886. ),
  887. syn_test_suite_helper:assert_wait(
  888. [],
  889. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"group-2">>])) end
  890. ),
  891. syn_test_suite_helper:assert_wait(
  892. [{PidRemoteOn2, "other-meta"}],
  893. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"group-2">>])) end
  894. ),
  895. 2 = syn:groups_count(default),
  896. 0 = syn:groups_count(default, node()),
  897. 1 = syn:groups_count(default, SlaveNode1),
  898. 2 = syn:groups_count(default, SlaveNode2),
  899. 2 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  900. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  901. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  902. 2 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  903. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  904. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  905. 1 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  906. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  907. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, <<"scoped-on-bc">>),
  908. syn_test_suite_helper:assert_wait(
  909. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  910. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  911. ),
  912. syn_test_suite_helper:assert_wait(
  913. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  914. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  915. ),
  916. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, <<"scoped-on-bc">>),
  917. syn_test_suite_helper:assert_wait(
  918. [{PidRemoteOn1, "scoped-meta-1"}],
  919. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  920. ),
  921. syn_test_suite_helper:assert_wait(
  922. [{PidRemoteOn2, "scoped-meta-2"}],
  923. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  924. ),
  925. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  926. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  927. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  928. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  929. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  930. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  931. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  932. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  933. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  934. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  935. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  936. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  937. %% partial netsplit (1 cannot see 2)
  938. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  939. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  940. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  941. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  942. %% retrieve
  943. syn_test_suite_helper:assert_wait(
  944. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  945. fun() -> lists:sort(syn:get_members(<<"common-group">>)) end
  946. ),
  947. syn_test_suite_helper:assert_wait(
  948. [{PidRemoteOn1, "meta-1"}],
  949. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"common-group">>])) end
  950. ),
  951. syn_test_suite_helper:assert_wait(
  952. [{PidRemoteOn2, "meta-2"}],
  953. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"common-group">>])) end
  954. ),
  955. syn_test_suite_helper:assert_wait(
  956. [],
  957. fun() -> lists:sort(syn:get_local_members(<<"common-group">>)) end
  958. ),
  959. syn_test_suite_helper:assert_wait(
  960. [{PidRemoteOn1, "meta-1"}],
  961. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"common-group">>])) end
  962. ),
  963. syn_test_suite_helper:assert_wait(
  964. [{PidRemoteOn2, "meta-2"}],
  965. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"common-group">>])) end
  966. ),
  967. syn_test_suite_helper:assert_wait(
  968. [{PidRemoteOn2, "other-meta"}],
  969. fun() -> lists:sort(syn:get_members(<<"group-2">>)) end
  970. ),
  971. syn_test_suite_helper:assert_wait(
  972. [],
  973. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"group-2">>])) end
  974. ),
  975. syn_test_suite_helper:assert_wait(
  976. [{PidRemoteOn2, "other-meta"}],
  977. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"group-2">>])) end
  978. ),
  979. syn_test_suite_helper:assert_wait(
  980. [],
  981. fun() -> lists:sort(syn:get_local_members(<<"group-2">>)) end
  982. ),
  983. syn_test_suite_helper:assert_wait(
  984. [],
  985. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"group-2">>])) end
  986. ),
  987. syn_test_suite_helper:assert_wait(
  988. [{PidRemoteOn2, "other-meta"}],
  989. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"group-2">>])) end
  990. ),
  991. 2 = syn:groups_count(default),
  992. 0 = syn:groups_count(default, node()),
  993. 1 = syn:groups_count(default, SlaveNode1),
  994. 2 = syn:groups_count(default, SlaveNode2),
  995. 1 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  996. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  997. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  998. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  999. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1000. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1001. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1002. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1003. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, <<"scoped-on-bc">>),
  1004. syn_test_suite_helper:assert_wait(
  1005. [{PidRemoteOn1, "scoped-meta-1"}],
  1006. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1007. ),
  1008. syn_test_suite_helper:assert_wait(
  1009. [{PidRemoteOn2, "scoped-meta-2"}],
  1010. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1011. ),
  1012. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1013. syn_test_suite_helper:assert_wait(
  1014. [{PidRemoteOn1, "scoped-meta-1"}],
  1015. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1016. ),
  1017. syn_test_suite_helper:assert_wait(
  1018. [{PidRemoteOn2, "scoped-meta-2"}],
  1019. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1020. ),
  1021. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1022. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1023. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1024. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1025. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1026. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1027. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1028. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1029. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1030. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1031. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1032. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1033. %% re-join
  1034. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1035. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1036. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1037. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1038. %% retrieve
  1039. syn_test_suite_helper:assert_wait(
  1040. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1041. fun() -> lists:sort(syn:get_members(<<"common-group">>)) end
  1042. ),
  1043. syn_test_suite_helper:assert_wait(
  1044. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1045. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"common-group">>])) end
  1046. ),
  1047. syn_test_suite_helper:assert_wait(
  1048. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1049. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"common-group">>])) end
  1050. ),
  1051. syn_test_suite_helper:assert_wait(
  1052. [],
  1053. fun() -> lists:sort(syn:get_local_members(<<"common-group">>)) end
  1054. ),
  1055. syn_test_suite_helper:assert_wait(
  1056. [{PidRemoteOn1, "meta-1"}],
  1057. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"common-group">>])) end
  1058. ),
  1059. syn_test_suite_helper:assert_wait(
  1060. [{PidRemoteOn2, "meta-2"}],
  1061. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"common-group">>])) end
  1062. ),
  1063. syn_test_suite_helper:assert_wait(
  1064. [{PidRemoteOn2, "other-meta"}],
  1065. fun() -> lists:sort(syn:get_members(<<"group-2">>)) end
  1066. ),
  1067. syn_test_suite_helper:assert_wait(
  1068. [{PidRemoteOn2, "other-meta"}],
  1069. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"group-2">>])) end
  1070. ),
  1071. syn_test_suite_helper:assert_wait(
  1072. [{PidRemoteOn2, "other-meta"}],
  1073. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"group-2">>])) end
  1074. ),
  1075. syn_test_suite_helper:assert_wait(
  1076. [],
  1077. fun() -> lists:sort(syn:get_local_members(<<"group-2">>)) end
  1078. ),
  1079. syn_test_suite_helper:assert_wait(
  1080. [],
  1081. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"group-2">>])) end
  1082. ),
  1083. syn_test_suite_helper:assert_wait(
  1084. [{PidRemoteOn2, "other-meta"}],
  1085. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"group-2">>])) end
  1086. ),
  1087. 2 = syn:groups_count(default),
  1088. 0 = syn:groups_count(default, node()),
  1089. 1 = syn:groups_count(default, SlaveNode1),
  1090. 2 = syn:groups_count(default, SlaveNode2),
  1091. 2 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  1092. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  1093. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  1094. 2 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  1095. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1096. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1097. 1 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1098. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1099. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, <<"scoped-on-bc">>),
  1100. syn_test_suite_helper:assert_wait(
  1101. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1102. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1103. ),
  1104. syn_test_suite_helper:assert_wait(
  1105. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1106. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1107. ),
  1108. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1109. syn_test_suite_helper:assert_wait(
  1110. [{PidRemoteOn1, "scoped-meta-1"}],
  1111. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1112. ),
  1113. syn_test_suite_helper:assert_wait(
  1114. [{PidRemoteOn2, "scoped-meta-2"}],
  1115. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1116. ),
  1117. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1118. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1119. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1120. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1121. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1122. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1123. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1124. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1125. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1126. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1127. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1128. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]).
  1129. three_nodes_custom_event_handler_joined_left(Config) ->
  1130. %% get slaves
  1131. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1132. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1133. %% add custom handler for callbacks
  1134. syn:set_event_handler(syn_test_event_handler_callbacks),
  1135. rpc:call(SlaveNode1, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  1136. rpc:call(SlaveNode2, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  1137. %% start syn on nodes
  1138. ok = syn:start(),
  1139. ok = rpc:call(SlaveNode1, syn, start, []),
  1140. ok = rpc:call(SlaveNode2, syn, start, []),
  1141. %% init
  1142. CurrentNode = node(),
  1143. %% start process
  1144. Pid = syn_test_suite_helper:start_process(),
  1145. Pid2 = syn_test_suite_helper:start_process(),
  1146. %% ---> on join
  1147. ok = syn:join("my-group", Pid, {recipient, self(), <<"meta">>}),
  1148. %% check callbacks called
  1149. syn_test_suite_helper:assert_received_messages([
  1150. {on_process_joined, CurrentNode, default, "my-group", Pid, <<"meta">>},
  1151. {on_process_joined, SlaveNode1, default, "my-group", Pid, <<"meta">>},
  1152. {on_process_joined, SlaveNode2, default, "my-group", Pid, <<"meta">>}
  1153. ]),
  1154. syn_test_suite_helper:assert_empty_queue(self()),
  1155. %% join from another node
  1156. ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid2, {recipient, self(), <<"meta-for-2">>}]),
  1157. %% check callbacks called
  1158. syn_test_suite_helper:assert_received_messages([
  1159. {on_process_joined, CurrentNode, default, "my-group", Pid2, <<"meta-for-2">>},
  1160. {on_process_joined, SlaveNode1, default, "my-group", Pid2, <<"meta-for-2">>},
  1161. {on_process_joined, SlaveNode2, default, "my-group", Pid2, <<"meta-for-2">>}
  1162. ]),
  1163. syn_test_suite_helper:assert_empty_queue(self()),
  1164. %% ---> on meta update
  1165. ok = syn:join("my-group", Pid, {recipient, self(), <<"new-meta-0">>}),
  1166. %% check callbacks called
  1167. syn_test_suite_helper:assert_received_messages([
  1168. {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta-0">>},
  1169. {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta-0">>},
  1170. {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta-0">>}
  1171. ]),
  1172. syn_test_suite_helper:assert_empty_queue(self()),
  1173. %% update meta from another node
  1174. ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid, {recipient, self(), <<"new-meta">>}]),
  1175. %% check callbacks called
  1176. syn_test_suite_helper:assert_received_messages([
  1177. {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
  1178. {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
  1179. {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
  1180. ]),
  1181. syn_test_suite_helper:assert_empty_queue(self()),
  1182. %% ---> on left
  1183. ok = syn:leave("my-group", Pid),
  1184. %% check callbacks called
  1185. syn_test_suite_helper:assert_received_messages([
  1186. {on_process_left, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
  1187. {on_process_left, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
  1188. {on_process_left, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
  1189. ]),
  1190. syn_test_suite_helper:assert_empty_queue(self()),
  1191. %% leave from another node
  1192. ok = rpc:call(SlaveNode1, syn, leave, ["my-group", Pid2]),
  1193. %% check callbacks called
  1194. syn_test_suite_helper:assert_received_messages([
  1195. {on_process_left, CurrentNode, default, "my-group", Pid2, <<"meta-for-2">>},
  1196. {on_process_left, SlaveNode1, default, "my-group", Pid2, <<"meta-for-2">>},
  1197. {on_process_left, SlaveNode2, default, "my-group", Pid2, <<"meta-for-2">>}
  1198. ]),
  1199. syn_test_suite_helper:assert_empty_queue(self()),
  1200. %% clean & check
  1201. syn_test_suite_helper:kill_process(Pid),
  1202. syn_test_suite_helper:assert_empty_queue(self()),
  1203. %% ---> after a netsplit
  1204. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  1205. syn:join(remote_on_1, PidRemoteOn1, {recipient, self(), <<"netsplit">>}),
  1206. %% check callbacks called
  1207. syn_test_suite_helper:assert_received_messages([
  1208. {on_process_joined, CurrentNode, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1209. {on_process_joined, SlaveNode1, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1210. {on_process_joined, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1211. ]),
  1212. syn_test_suite_helper:assert_empty_queue(self()),
  1213. %% partial netsplit (1 cannot see 2)
  1214. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1215. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1216. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1217. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1218. %% check callbacks called
  1219. syn_test_suite_helper:assert_received_messages([
  1220. {on_process_left, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1221. ]),
  1222. syn_test_suite_helper:assert_empty_queue(self()),
  1223. %% ---> after a re-join
  1224. %% re-join
  1225. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1226. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1227. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1228. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1229. %% check callbacks called
  1230. syn_test_suite_helper:assert_received_messages([
  1231. {on_process_joined, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1232. ]),
  1233. syn_test_suite_helper:assert_empty_queue(self()),
  1234. %% clean
  1235. syn_test_suite_helper:kill_process(PidRemoteOn1),
  1236. %% check callbacks called
  1237. syn_test_suite_helper:assert_received_messages([
  1238. {on_process_left, CurrentNode, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1239. {on_process_left, SlaveNode1, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1240. {on_process_left, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1241. ]),
  1242. syn_test_suite_helper:assert_empty_queue(self()),
  1243. %% ---> don't call on monitor rebuild
  1244. %% crash the scope process on local
  1245. syn_test_suite_helper:kill_process(syn_groups_default),
  1246. %% no messages
  1247. syn_test_suite_helper:assert_wait(
  1248. ok,
  1249. fun() -> syn_test_suite_helper:assert_empty_queue(self()) end
  1250. ).