syn_groups_SUITE.erl 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614
  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. false = syn:is_member({group, "one"}, Pid),
  322. false = syn:is_member({group, "one"}, PidWithMeta),
  323. false = syn:is_member({group, "one"}, PidRemoteOn1),
  324. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, Pid]),
  325. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidWithMeta]),
  326. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  327. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, Pid]),
  328. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidWithMeta]),
  329. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  330. [] = syn:get_members({group, "two"}),
  331. [] = rpc:call(SlaveNode1, syn, get_members, [{group, "two"}]),
  332. [] = rpc:call(SlaveNode2, syn, get_members, [{group, "two"}]),
  333. false = syn:is_member({group, "two"}, Pid),
  334. false = syn:is_member({group, "two"}, PidWithMeta),
  335. false = syn:is_member({group, "two"}, PidRemoteOn1),
  336. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, Pid]),
  337. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidWithMeta]),
  338. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  339. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, Pid]),
  340. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidWithMeta]),
  341. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  342. [] = syn:get_local_members({group, "one"}),
  343. [] = rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}]),
  344. [] = rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}]),
  345. false = syn:is_local_member({group, "one"}, Pid),
  346. false = syn:is_local_member({group, "one"}, PidWithMeta),
  347. false = syn:is_local_member({group, "one"}, PidRemoteOn1),
  348. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, Pid]),
  349. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  350. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  351. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, Pid]),
  352. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  353. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  354. [] = syn:get_local_members({group, "two"}),
  355. [] = rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}]),
  356. [] = rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}]),
  357. false = syn:is_local_member({group, "two"}, Pid),
  358. false = syn:is_local_member({group, "two"}, PidWithMeta),
  359. false = syn:is_local_member({group, "two"}, PidRemoteOn1),
  360. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, Pid]),
  361. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  362. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  363. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, Pid]),
  364. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  365. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  366. 0 = syn:groups_count(default),
  367. 0 = syn:groups_count(default, node()),
  368. 0 = syn:groups_count(default, SlaveNode1),
  369. 0 = syn:groups_count(default, SlaveNode2),
  370. %% join
  371. ok = syn:join({group, "one"}, Pid),
  372. ok = syn:join({group, "one"}, PidWithMeta, <<"with meta">>),
  373. ok = syn:join({group, "one"}, PidRemoteOn1),
  374. ok = syn:join({group, "two"}, Pid),
  375. ok = syn:join({group, "two"}, PidWithMeta, "with-meta-2"),
  376. %% errors
  377. {error, not_alive} = syn:join({"pid not alive"}, list_to_pid("<0.9999.0>")),
  378. {error, not_in_group} = syn:leave({group, "three"}, Pid),
  379. %% retrieve
  380. syn_test_suite_helper:assert_wait(
  381. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  382. fun() -> lists:sort(syn:get_members({group, "one"})) end
  383. ),
  384. syn_test_suite_helper:assert_wait(
  385. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  386. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "one"}])) end
  387. ),
  388. syn_test_suite_helper:assert_wait(
  389. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  390. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "one"}])) end
  391. ),
  392. true = syn:is_member({group, "one"}, Pid),
  393. true = syn:is_member({group, "one"}, PidWithMeta),
  394. true = syn:is_member({group, "one"}, PidRemoteOn1),
  395. true = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, Pid]),
  396. true = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidWithMeta]),
  397. true = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  398. true = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, Pid]),
  399. true = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidWithMeta]),
  400. true = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  401. syn_test_suite_helper:assert_wait(
  402. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  403. fun() -> lists:sort(syn:get_local_members({group, "one"})) end
  404. ),
  405. syn_test_suite_helper:assert_wait(
  406. [{PidRemoteOn1, undefined}],
  407. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}])) end
  408. ),
  409. syn_test_suite_helper:assert_wait(
  410. [],
  411. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}])) end
  412. ),
  413. true = syn:is_local_member({group, "one"}, Pid),
  414. true = syn:is_local_member({group, "one"}, PidWithMeta),
  415. false = syn:is_local_member({group, "one"}, PidRemoteOn1),
  416. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, Pid]),
  417. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  418. true = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  419. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, Pid]),
  420. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  421. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  422. syn_test_suite_helper:assert_wait(
  423. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  424. fun() -> lists:sort(syn:get_members({group, "two"})) end
  425. ),
  426. syn_test_suite_helper:assert_wait(
  427. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  428. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "two"}])) end
  429. ),
  430. syn_test_suite_helper:assert_wait(
  431. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  432. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "two"}])) end
  433. ),
  434. true = syn:is_member({group, "two"}, Pid),
  435. true = syn:is_member({group, "two"}, PidWithMeta),
  436. false = syn:is_member({group, "two"}, PidRemoteOn1),
  437. true = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, Pid]),
  438. true = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidWithMeta]),
  439. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  440. true = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, Pid]),
  441. true = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidWithMeta]),
  442. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  443. syn_test_suite_helper:assert_wait(
  444. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  445. fun() -> lists:sort(syn:get_local_members({group, "two"})) end
  446. ),
  447. syn_test_suite_helper:assert_wait(
  448. [],
  449. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}])) end
  450. ),
  451. syn_test_suite_helper:assert_wait(
  452. [],
  453. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}])) end
  454. ),
  455. true = syn:is_local_member({group, "two"}, Pid),
  456. true = syn:is_local_member({group, "two"}, PidWithMeta),
  457. false = syn:is_local_member({group, "two"}, PidRemoteOn1),
  458. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, Pid]),
  459. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  460. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  461. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, Pid]),
  462. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  463. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  464. 2 = syn:groups_count(default),
  465. 2 = syn:groups_count(default, node()),
  466. 1 = syn:groups_count(default, SlaveNode1),
  467. 0 = syn:groups_count(default, SlaveNode2),
  468. %% re-join to edit meta
  469. ok = syn:join({group, "one"}, PidWithMeta, <<"with updated meta">>),
  470. ok = rpc:call(SlaveNode2, syn, join, [{group, "one"}, PidRemoteOn1, added_meta]), %% updated on slave 2
  471. %% retrieve
  472. syn_test_suite_helper:assert_wait(
  473. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  474. fun() -> lists:sort(syn:get_members({group, "one"})) end
  475. ),
  476. syn_test_suite_helper:assert_wait(
  477. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  478. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "one"}])) end
  479. ),
  480. syn_test_suite_helper:assert_wait(
  481. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  482. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "one"}])) end
  483. ),
  484. syn_test_suite_helper:assert_wait(
  485. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  486. fun() -> lists:sort(syn:get_local_members({group, "one"})) end
  487. ),
  488. syn_test_suite_helper:assert_wait(
  489. [{PidRemoteOn1, added_meta}],
  490. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}])) end
  491. ),
  492. syn_test_suite_helper:assert_wait(
  493. [],
  494. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}])) end
  495. ),
  496. syn_test_suite_helper:assert_wait(
  497. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  498. fun() -> lists:sort(syn:get_members({group, "two"})) end
  499. ),
  500. syn_test_suite_helper:assert_wait(
  501. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  502. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "two"}])) end
  503. ),
  504. syn_test_suite_helper:assert_wait(
  505. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  506. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "two"}])) end
  507. ),
  508. syn_test_suite_helper:assert_wait(
  509. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  510. fun() -> lists:sort(syn:get_local_members({group, "two"})) end
  511. ),
  512. syn_test_suite_helper:assert_wait(
  513. [],
  514. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}])) end
  515. ),
  516. syn_test_suite_helper:assert_wait(
  517. [],
  518. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}])) end
  519. ),
  520. 2 = syn:groups_count(default),
  521. 2 = syn:groups_count(default, node()),
  522. 1 = syn:groups_count(default, SlaveNode1),
  523. 0 = syn:groups_count(default, SlaveNode2),
  524. %% crash scope process to ensure that monitors get recreated
  525. exit(whereis(syn_groups_default), kill),
  526. syn_test_suite_helper:wait_process_name_ready(syn_groups_default),
  527. %% kill process
  528. syn_test_suite_helper:kill_process(Pid),
  529. syn_test_suite_helper:kill_process(PidRemoteOn1),
  530. %% leave
  531. ok = syn:leave({group, "one"}, PidWithMeta),
  532. %% retrieve
  533. syn_test_suite_helper:assert_wait(
  534. [],
  535. fun() -> lists:sort(syn:get_members({group, "one"})) end
  536. ),
  537. syn_test_suite_helper:assert_wait(
  538. [],
  539. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "one"}])) end
  540. ),
  541. syn_test_suite_helper:assert_wait(
  542. [],
  543. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "one"}])) end
  544. ),
  545. false = syn:is_member({group, "one"}, Pid),
  546. false = syn:is_member({group, "one"}, PidWithMeta),
  547. false = syn:is_member({group, "one"}, PidRemoteOn1),
  548. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, Pid]),
  549. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidWithMeta]),
  550. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  551. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, Pid]),
  552. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidWithMeta]),
  553. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  554. syn_test_suite_helper:assert_wait(
  555. [],
  556. fun() -> lists:sort(syn:get_local_members({group, "one"})) end
  557. ),
  558. syn_test_suite_helper:assert_wait(
  559. [],
  560. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "one"}])) end
  561. ),
  562. syn_test_suite_helper:assert_wait(
  563. [],
  564. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "one"}])) end
  565. ),
  566. false = syn:is_local_member({group, "one"}, Pid),
  567. false = syn:is_local_member({group, "one"}, PidWithMeta),
  568. false = syn:is_local_member({group, "one"}, PidRemoteOn1),
  569. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, Pid]),
  570. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  571. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  572. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, Pid]),
  573. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  574. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  575. syn_test_suite_helper:assert_wait(
  576. [{PidWithMeta, "with-meta-2"}],
  577. fun() -> lists:sort(syn:get_members({group, "two"})) end
  578. ),
  579. syn_test_suite_helper:assert_wait(
  580. [{PidWithMeta, "with-meta-2"}],
  581. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [{group, "two"}])) end
  582. ),
  583. syn_test_suite_helper:assert_wait(
  584. [{PidWithMeta, "with-meta-2"}],
  585. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [{group, "two"}])) end
  586. ),
  587. false = syn:is_member({group, "two"}, Pid),
  588. true = syn:is_member({group, "two"}, PidWithMeta),
  589. false = syn:is_member({group, "two"}, PidRemoteOn1),
  590. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, Pid]),
  591. true = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidWithMeta]),
  592. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  593. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, Pid]),
  594. true = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidWithMeta]),
  595. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  596. syn_test_suite_helper:assert_wait(
  597. [{PidWithMeta, "with-meta-2"}],
  598. fun() -> lists:sort(syn:get_local_members({group, "two"})) end
  599. ),
  600. syn_test_suite_helper:assert_wait(
  601. [],
  602. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [{group, "two"}])) end
  603. ),
  604. syn_test_suite_helper:assert_wait(
  605. [],
  606. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [{group, "two"}])) end
  607. ),
  608. false = syn:is_local_member({group, "two"}, Pid),
  609. true = syn:is_local_member({group, "two"}, PidWithMeta),
  610. false = syn:is_local_member({group, "two"}, PidRemoteOn1),
  611. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, Pid]),
  612. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  613. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  614. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, Pid]),
  615. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  616. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  617. 1 = syn:groups_count(default),
  618. 1 = syn:groups_count(default, node()),
  619. 0 = syn:groups_count(default, SlaveNode1),
  620. 0 = syn:groups_count(default, SlaveNode2),
  621. %% errors
  622. {error, not_in_group} = syn:leave({group, "one"}, PidWithMeta).
  623. three_nodes_join_leave_and_monitor_custom_scope(Config) ->
  624. %% get slaves
  625. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  626. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  627. %% start syn on nodes
  628. ok = syn:start(),
  629. ok = rpc:call(SlaveNode1, syn, start, []),
  630. ok = rpc:call(SlaveNode2, syn, start, []),
  631. %% add custom scopes
  632. ok = syn:add_node_to_scope(custom_scope_ab),
  633. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc]]),
  634. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  635. %% start processes
  636. Pid = syn_test_suite_helper:start_process(),
  637. PidWithMeta = syn_test_suite_helper:start_process(),
  638. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  639. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  640. %% check
  641. [] = syn:get_members(custom_scope_ab, {group, "one"}),
  642. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}]),
  643. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  644. false = syn:is_member(custom_scope_ab, {group, "one"}, Pid),
  645. false = syn:is_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  646. false = syn:is_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  647. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  648. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  649. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  650. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  651. [] = syn:get_local_members(custom_scope_ab, {group, "one"}),
  652. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  653. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  654. false = syn:is_local_member(custom_scope_ab, {group, "one"}, Pid),
  655. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  656. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  657. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  658. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  659. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  660. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  661. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "one"}),
  662. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "one"}]),
  663. [] = rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "one"}]),
  664. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "one"}),
  665. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "one"}]),
  666. [] = rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "one"}]),
  667. [] = syn:get_members(custom_scope_ab, {group, "two"}),
  668. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}]),
  669. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  670. false = syn:is_member(custom_scope_ab, {group, "two"}, Pid),
  671. false = syn:is_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  672. false = syn:is_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  673. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  674. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  675. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  676. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  677. [] = syn:get_local_members(custom_scope_ab, {group, "two"}),
  678. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  679. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  680. false = syn:is_local_member(custom_scope_ab, {group, "two"}, Pid),
  681. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  682. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  683. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  684. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  685. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  686. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  687. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  688. [] = rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}]),
  689. [] = rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}]),
  690. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  691. [] = rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}]),
  692. [] = rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}]),
  693. %% join
  694. ok = syn:join(custom_scope_ab, {group, "one"}, Pid),
  695. ok = syn:join(custom_scope_ab, {group, "one"}, PidWithMeta, <<"with meta">>),
  696. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, {group, "two"}, PidRemoteOn1]),
  697. ok = syn:join(custom_scope_ab, {group, "two"}, Pid),
  698. ok = syn:join(custom_scope_ab, {group, "two"}, PidWithMeta, "with-meta-2"),
  699. %% errors
  700. {error, not_alive} = syn:join({"pid not alive"}, list_to_pid("<0.9999.0>")),
  701. {error, not_in_group} = syn:leave({group, "three"}, Pid),
  702. {'EXIT', {{invalid_scope, custom_scope_ab}, _}} = catch syn:join(custom_scope_ab, {group, "one"}, PidRemoteOn2),
  703. %% retrieve
  704. syn_test_suite_helper:assert_wait(
  705. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  706. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "one"})) end
  707. ),
  708. syn_test_suite_helper:assert_wait(
  709. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  710. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}])) end
  711. ),
  712. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  713. true = syn:is_member(custom_scope_ab, {group, "one"}, Pid),
  714. true = syn:is_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  715. false = syn:is_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  716. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  717. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  718. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  719. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  720. syn_test_suite_helper:assert_wait(
  721. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  722. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "one"})) end
  723. ),
  724. syn_test_suite_helper:assert_wait(
  725. [],
  726. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}])) end
  727. ),
  728. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  729. true = syn:is_local_member(custom_scope_ab, {group, "one"}, Pid),
  730. true = syn:is_local_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  731. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  732. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  733. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  734. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  735. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  736. syn_test_suite_helper:assert_wait(
  737. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  738. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "two"})) end
  739. ),
  740. syn_test_suite_helper:assert_wait(
  741. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  742. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}])) end
  743. ),
  744. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  745. true = syn:is_member(custom_scope_ab, {group, "two"}, Pid),
  746. true = syn:is_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  747. false = syn:is_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  748. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  749. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  750. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  751. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  752. syn_test_suite_helper:assert_wait(
  753. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  754. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "two"})) end
  755. ),
  756. syn_test_suite_helper:assert_wait(
  757. [],
  758. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}])) end
  759. ),
  760. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  761. true = syn:is_local_member(custom_scope_ab, {group, "two"}, Pid),
  762. true = syn:is_local_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  763. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  764. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  765. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  766. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  767. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  768. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  769. syn_test_suite_helper:assert_wait(
  770. [{PidRemoteOn1, undefined}],
  771. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  772. ),
  773. syn_test_suite_helper:assert_wait(
  774. [{PidRemoteOn1, undefined}],
  775. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  776. ),
  777. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  778. syn_test_suite_helper:assert_wait(
  779. [{PidRemoteOn1, undefined}],
  780. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  781. ),
  782. syn_test_suite_helper:assert_wait(
  783. [],
  784. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  785. ),
  786. 2 = syn:groups_count(custom_scope_ab),
  787. 2 = syn:groups_count(custom_scope_ab, node()),
  788. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  789. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  790. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  791. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  792. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  793. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  794. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  795. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  796. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  797. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  798. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  799. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  800. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  801. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  802. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  803. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  804. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  805. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  806. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  807. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  808. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  809. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  810. %% re-join to edit meta
  811. ok = syn:join(custom_scope_ab, {group, "one"}, PidWithMeta, <<"with updated meta">>),
  812. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, {group, "two"}, PidRemoteOn1, added_meta]), %% updated on slave 2
  813. %% retrieve
  814. syn_test_suite_helper:assert_wait(
  815. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  816. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "one"})) end
  817. ),
  818. syn_test_suite_helper:assert_wait(
  819. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  820. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}])) end
  821. ),
  822. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  823. syn_test_suite_helper:assert_wait(
  824. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  825. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "one"})) end
  826. ),
  827. syn_test_suite_helper:assert_wait(
  828. [],
  829. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}])) end
  830. ),
  831. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  832. syn_test_suite_helper:assert_wait(
  833. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  834. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "two"})) end
  835. ),
  836. syn_test_suite_helper:assert_wait(
  837. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  838. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}])) end
  839. ),
  840. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  841. syn_test_suite_helper:assert_wait(
  842. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  843. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "two"})) end
  844. ),
  845. syn_test_suite_helper:assert_wait(
  846. [],
  847. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}])) end
  848. ),
  849. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  850. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  851. syn_test_suite_helper:assert_wait(
  852. [{PidRemoteOn1, added_meta}],
  853. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  854. ),
  855. syn_test_suite_helper:assert_wait(
  856. [{PidRemoteOn1, added_meta}],
  857. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  858. ),
  859. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  860. syn_test_suite_helper:assert_wait(
  861. [{PidRemoteOn1, added_meta}],
  862. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  863. ),
  864. syn_test_suite_helper:assert_wait(
  865. [],
  866. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  867. ),
  868. 2 = syn:groups_count(custom_scope_ab),
  869. 2 = syn:groups_count(custom_scope_ab, node()),
  870. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  871. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  872. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  873. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  874. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  875. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  876. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  877. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  878. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  879. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  880. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  881. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  882. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  883. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  884. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  885. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  886. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  887. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  888. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  889. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  890. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  891. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  892. %% crash scope process to ensure that monitors get recreated
  893. exit(whereis(syn_groups_custom_scope_ab), kill),
  894. syn_test_suite_helper:wait_process_name_ready(syn_groups_custom_scope_ab),
  895. %% kill process
  896. syn_test_suite_helper:kill_process(Pid),
  897. syn_test_suite_helper:kill_process(PidRemoteOn1),
  898. %% leave
  899. ok = syn:leave(custom_scope_ab, {group, "one"}, PidWithMeta),
  900. %% retrieve
  901. syn_test_suite_helper:assert_wait(
  902. [],
  903. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "one"})) end
  904. ),
  905. syn_test_suite_helper:assert_wait(
  906. [],
  907. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "one"}])) end
  908. ),
  909. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "one"}]),
  910. false = syn:is_member(custom_scope_ab, {group, "one"}, Pid),
  911. false = syn:is_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  912. false = syn:is_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  913. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  914. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  915. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  916. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  917. syn_test_suite_helper:assert_wait(
  918. [],
  919. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "one"})) end
  920. ),
  921. syn_test_suite_helper:assert_wait(
  922. [],
  923. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "one"}])) end
  924. ),
  925. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "one"}]),
  926. false = syn:is_local_member(custom_scope_ab, {group, "one"}, Pid),
  927. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  928. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  929. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  930. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  931. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  932. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  933. syn_test_suite_helper:assert_wait(
  934. [{PidWithMeta, "with-meta-2"}],
  935. fun() -> lists:sort(syn:get_members(custom_scope_ab, {group, "two"})) end
  936. ),
  937. syn_test_suite_helper:assert_wait(
  938. [{PidWithMeta, "with-meta-2"}],
  939. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_ab, {group, "two"}])) end
  940. ),
  941. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_members, [custom_scope_ab, {group, "two"}]),
  942. false = syn:is_member(custom_scope_ab, {group, "two"}, Pid),
  943. true = syn:is_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  944. false = syn:is_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  945. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  946. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  947. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  948. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  949. syn_test_suite_helper:assert_wait(
  950. [{PidWithMeta, "with-meta-2"}],
  951. fun() -> lists:sort(syn:get_local_members(custom_scope_ab, {group, "two"})) end
  952. ),
  953. syn_test_suite_helper:assert_wait(
  954. [],
  955. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_ab, {group, "two"}])) end
  956. ),
  957. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_ab, {group, "two"}]),
  958. false = syn:is_local_member(custom_scope_ab, {group, "two"}, Pid),
  959. true = syn:is_local_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  960. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  961. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  962. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  963. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  964. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  965. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, {group, "two"}),
  966. syn_test_suite_helper:assert_wait(
  967. [],
  968. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  969. ),
  970. syn_test_suite_helper:assert_wait(
  971. [], fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, {group, "two"}])) end
  972. ),
  973. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, {group, "two"}),
  974. syn_test_suite_helper:assert_wait(
  975. [],
  976. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  977. ),
  978. syn_test_suite_helper:assert_wait(
  979. [], fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, {group, "two"}])) end
  980. ),
  981. 1 = syn:groups_count(custom_scope_ab),
  982. 1 = syn:groups_count(custom_scope_ab, node()),
  983. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  984. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  985. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  986. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  987. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  988. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  989. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  990. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  991. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  992. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  993. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  994. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  995. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  996. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  997. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  998. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  999. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  1000. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  1001. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1002. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1003. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1004. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1005. %% errors
  1006. {error, not_in_group} = syn:leave(custom_scope_ab, {group, "one"}, PidWithMeta).
  1007. three_nodes_cluster_changes(Config) ->
  1008. %% get slaves
  1009. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1010. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1011. %% disconnect 1 from 2
  1012. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1013. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1014. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1015. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1016. %% start syn on 1 and 2, nodes don't know of each other
  1017. ok = rpc:call(SlaveNode1, syn, start, []),
  1018. ok = rpc:call(SlaveNode2, syn, start, []),
  1019. %% add custom scopes
  1020. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_bc]]),
  1021. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  1022. %% start processes
  1023. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  1024. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  1025. %% join
  1026. ok = rpc:call(SlaveNode1, syn, join, [<<"common-group">>, PidRemoteOn1, "meta-1"]),
  1027. ok = rpc:call(SlaveNode2, syn, join, [<<"common-group">>, PidRemoteOn2, "meta-2"]),
  1028. ok = rpc:call(SlaveNode2, syn, join, [<<"group-2">>, PidRemoteOn2, "other-meta"]),
  1029. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, <<"scoped-on-bc">>, PidRemoteOn1, "scoped-meta-1"]),
  1030. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, <<"scoped-on-bc">>, PidRemoteOn2, "scoped-meta-2"]),
  1031. %% form full cluster
  1032. ok = syn:start(),
  1033. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1034. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1035. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1036. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1037. syn_test_suite_helper:wait_process_name_ready(syn_groups_default),
  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. %% partial netsplit (1 cannot see 2)
  1130. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1131. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1132. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1133. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1134. %% retrieve
  1135. syn_test_suite_helper:assert_wait(
  1136. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1137. fun() -> lists:sort(syn:get_members(<<"common-group">>)) end
  1138. ),
  1139. syn_test_suite_helper:assert_wait(
  1140. [{PidRemoteOn1, "meta-1"}],
  1141. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"common-group">>])) end
  1142. ),
  1143. syn_test_suite_helper:assert_wait(
  1144. [{PidRemoteOn2, "meta-2"}],
  1145. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"common-group">>])) end
  1146. ),
  1147. syn_test_suite_helper:assert_wait(
  1148. [],
  1149. fun() -> lists:sort(syn:get_local_members(<<"common-group">>)) end
  1150. ),
  1151. syn_test_suite_helper:assert_wait(
  1152. [{PidRemoteOn1, "meta-1"}],
  1153. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"common-group">>])) end
  1154. ),
  1155. syn_test_suite_helper:assert_wait(
  1156. [{PidRemoteOn2, "meta-2"}],
  1157. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"common-group">>])) end
  1158. ),
  1159. syn_test_suite_helper:assert_wait(
  1160. [{PidRemoteOn2, "other-meta"}],
  1161. fun() -> lists:sort(syn:get_members(<<"group-2">>)) end
  1162. ),
  1163. syn_test_suite_helper:assert_wait(
  1164. [],
  1165. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"group-2">>])) end
  1166. ),
  1167. syn_test_suite_helper:assert_wait(
  1168. [{PidRemoteOn2, "other-meta"}],
  1169. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"group-2">>])) end
  1170. ),
  1171. syn_test_suite_helper:assert_wait(
  1172. [],
  1173. fun() -> lists:sort(syn:get_local_members(<<"group-2">>)) end
  1174. ),
  1175. syn_test_suite_helper:assert_wait(
  1176. [],
  1177. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"group-2">>])) end
  1178. ),
  1179. syn_test_suite_helper:assert_wait(
  1180. [{PidRemoteOn2, "other-meta"}],
  1181. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"group-2">>])) end
  1182. ),
  1183. 2 = syn:groups_count(default),
  1184. 0 = syn:groups_count(default, node()),
  1185. 1 = syn:groups_count(default, SlaveNode1),
  1186. 2 = syn:groups_count(default, SlaveNode2),
  1187. 1 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  1188. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  1189. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  1190. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  1191. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1192. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1193. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1194. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1195. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, <<"scoped-on-bc">>),
  1196. syn_test_suite_helper:assert_wait(
  1197. [{PidRemoteOn1, "scoped-meta-1"}],
  1198. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1199. ),
  1200. syn_test_suite_helper:assert_wait(
  1201. [{PidRemoteOn2, "scoped-meta-2"}],
  1202. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1203. ),
  1204. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1205. syn_test_suite_helper:assert_wait(
  1206. [{PidRemoteOn1, "scoped-meta-1"}],
  1207. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1208. ),
  1209. syn_test_suite_helper:assert_wait(
  1210. [{PidRemoteOn2, "scoped-meta-2"}],
  1211. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1212. ),
  1213. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1214. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1215. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1216. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1217. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1218. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1219. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1220. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1221. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1222. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1223. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1224. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1225. %% re-join
  1226. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1227. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1228. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1229. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1230. %% retrieve
  1231. syn_test_suite_helper:assert_wait(
  1232. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1233. fun() -> lists:sort(syn:get_members(<<"common-group">>)) end
  1234. ),
  1235. syn_test_suite_helper:assert_wait(
  1236. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1237. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"common-group">>])) end
  1238. ),
  1239. syn_test_suite_helper:assert_wait(
  1240. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1241. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"common-group">>])) end
  1242. ),
  1243. syn_test_suite_helper:assert_wait(
  1244. [],
  1245. fun() -> lists:sort(syn:get_local_members(<<"common-group">>)) end
  1246. ),
  1247. syn_test_suite_helper:assert_wait(
  1248. [{PidRemoteOn1, "meta-1"}],
  1249. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"common-group">>])) end
  1250. ),
  1251. syn_test_suite_helper:assert_wait(
  1252. [{PidRemoteOn2, "meta-2"}],
  1253. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"common-group">>])) end
  1254. ),
  1255. syn_test_suite_helper:assert_wait(
  1256. [{PidRemoteOn2, "other-meta"}],
  1257. fun() -> lists:sort(syn:get_members(<<"group-2">>)) end
  1258. ),
  1259. syn_test_suite_helper:assert_wait(
  1260. [{PidRemoteOn2, "other-meta"}],
  1261. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [<<"group-2">>])) end
  1262. ),
  1263. syn_test_suite_helper:assert_wait(
  1264. [{PidRemoteOn2, "other-meta"}],
  1265. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [<<"group-2">>])) end
  1266. ),
  1267. syn_test_suite_helper:assert_wait(
  1268. [],
  1269. fun() -> lists:sort(syn:get_local_members(<<"group-2">>)) end
  1270. ),
  1271. syn_test_suite_helper:assert_wait(
  1272. [],
  1273. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [<<"group-2">>])) end
  1274. ),
  1275. syn_test_suite_helper:assert_wait(
  1276. [{PidRemoteOn2, "other-meta"}],
  1277. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [<<"group-2">>])) end
  1278. ),
  1279. 2 = syn:groups_count(default),
  1280. 0 = syn:groups_count(default, node()),
  1281. 1 = syn:groups_count(default, SlaveNode1),
  1282. 2 = syn:groups_count(default, SlaveNode2),
  1283. 2 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  1284. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  1285. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  1286. 2 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  1287. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1288. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1289. 1 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1290. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1291. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_members(custom_scope_bc, <<"scoped-on-bc">>),
  1292. syn_test_suite_helper:assert_wait(
  1293. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1294. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1295. ),
  1296. syn_test_suite_helper:assert_wait(
  1297. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1298. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1299. ),
  1300. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:get_local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1301. syn_test_suite_helper:assert_wait(
  1302. [{PidRemoteOn1, "scoped-meta-1"}],
  1303. fun() -> lists:sort(rpc:call(SlaveNode1, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1304. ),
  1305. syn_test_suite_helper:assert_wait(
  1306. [{PidRemoteOn2, "scoped-meta-2"}],
  1307. fun() -> lists:sort(rpc:call(SlaveNode2, syn, get_local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1308. ),
  1309. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1310. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1311. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1312. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1313. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1314. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1315. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1316. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1317. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1318. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1319. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1320. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]).
  1321. three_nodes_custom_event_handler_joined_left(Config) ->
  1322. %% get slaves
  1323. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1324. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1325. %% add custom handler for callbacks
  1326. syn:set_event_handler(syn_test_event_handler_callbacks),
  1327. rpc:call(SlaveNode1, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  1328. rpc:call(SlaveNode2, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  1329. %% start syn on nodes
  1330. ok = syn:start(),
  1331. ok = rpc:call(SlaveNode1, syn, start, []),
  1332. ok = rpc:call(SlaveNode2, syn, start, []),
  1333. %% init
  1334. CurrentNode = node(),
  1335. %% start process
  1336. Pid = syn_test_suite_helper:start_process(),
  1337. Pid2 = syn_test_suite_helper:start_process(),
  1338. %% ---> on join
  1339. ok = syn:join("my-group", Pid, {recipient, self(), <<"meta">>}),
  1340. %% check callbacks called
  1341. syn_test_suite_helper:assert_received_messages([
  1342. {on_process_joined, CurrentNode, default, "my-group", Pid, <<"meta">>},
  1343. {on_process_joined, SlaveNode1, default, "my-group", Pid, <<"meta">>},
  1344. {on_process_joined, SlaveNode2, default, "my-group", Pid, <<"meta">>}
  1345. ]),
  1346. syn_test_suite_helper:assert_empty_queue(self()),
  1347. %% join from another node
  1348. ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid2, {recipient, self(), <<"meta-for-2">>}]),
  1349. %% check callbacks called
  1350. syn_test_suite_helper:assert_received_messages([
  1351. {on_process_joined, CurrentNode, default, "my-group", Pid2, <<"meta-for-2">>},
  1352. {on_process_joined, SlaveNode1, default, "my-group", Pid2, <<"meta-for-2">>},
  1353. {on_process_joined, SlaveNode2, default, "my-group", Pid2, <<"meta-for-2">>}
  1354. ]),
  1355. syn_test_suite_helper:assert_empty_queue(self()),
  1356. %% ---> on meta update
  1357. ok = syn:join("my-group", Pid, {recipient, self(), <<"new-meta-0">>}),
  1358. %% check callbacks called
  1359. syn_test_suite_helper:assert_received_messages([
  1360. {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta-0">>},
  1361. {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta-0">>},
  1362. {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta-0">>}
  1363. ]),
  1364. syn_test_suite_helper:assert_empty_queue(self()),
  1365. %% update meta from another node
  1366. ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid, {recipient, self(), <<"new-meta">>}]),
  1367. %% check callbacks called
  1368. syn_test_suite_helper:assert_received_messages([
  1369. {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
  1370. {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
  1371. {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
  1372. ]),
  1373. syn_test_suite_helper:assert_empty_queue(self()),
  1374. %% ---> on left
  1375. ok = syn:leave("my-group", Pid),
  1376. %% check callbacks called
  1377. syn_test_suite_helper:assert_received_messages([
  1378. {on_process_left, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
  1379. {on_process_left, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
  1380. {on_process_left, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
  1381. ]),
  1382. syn_test_suite_helper:assert_empty_queue(self()),
  1383. %% leave from another node
  1384. ok = rpc:call(SlaveNode1, syn, leave, ["my-group", Pid2]),
  1385. %% check callbacks called
  1386. syn_test_suite_helper:assert_received_messages([
  1387. {on_process_left, CurrentNode, default, "my-group", Pid2, <<"meta-for-2">>},
  1388. {on_process_left, SlaveNode1, default, "my-group", Pid2, <<"meta-for-2">>},
  1389. {on_process_left, SlaveNode2, default, "my-group", Pid2, <<"meta-for-2">>}
  1390. ]),
  1391. syn_test_suite_helper:assert_empty_queue(self()),
  1392. %% clean & check
  1393. syn_test_suite_helper:kill_process(Pid),
  1394. syn_test_suite_helper:assert_empty_queue(self()),
  1395. %% ---> after a netsplit
  1396. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  1397. syn:join(remote_on_1, PidRemoteOn1, {recipient, self(), <<"netsplit">>}),
  1398. %% check callbacks called
  1399. syn_test_suite_helper:assert_received_messages([
  1400. {on_process_joined, CurrentNode, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1401. {on_process_joined, SlaveNode1, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1402. {on_process_joined, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1403. ]),
  1404. syn_test_suite_helper:assert_empty_queue(self()),
  1405. %% partial netsplit (1 cannot see 2)
  1406. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1407. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1408. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1409. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1410. %% check callbacks called
  1411. syn_test_suite_helper:assert_received_messages([
  1412. {on_process_left, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1413. ]),
  1414. syn_test_suite_helper:assert_empty_queue(self()),
  1415. %% ---> after a re-join
  1416. %% re-join
  1417. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1418. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1419. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1420. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1421. %% check callbacks called
  1422. syn_test_suite_helper:assert_received_messages([
  1423. {on_process_joined, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1424. ]),
  1425. syn_test_suite_helper:assert_empty_queue(self()),
  1426. %% clean
  1427. syn_test_suite_helper:kill_process(PidRemoteOn1),
  1428. %% check callbacks called
  1429. syn_test_suite_helper:assert_received_messages([
  1430. {on_process_left, CurrentNode, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1431. {on_process_left, SlaveNode1, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1432. {on_process_left, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1433. ]),
  1434. syn_test_suite_helper:assert_empty_queue(self()),
  1435. %% ---> don't call on monitor rebuild
  1436. %% crash the scope process on local
  1437. syn_test_suite_helper:kill_process(syn_groups_default),
  1438. %% no messages
  1439. syn_test_suite_helper:assert_wait(
  1440. ok,
  1441. fun() -> syn_test_suite_helper:assert_empty_queue(self()) end
  1442. ).