syn_groups_SUITE.erl 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857
  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. three_nodes_publish_default_scope/1,
  41. three_nodes_publish_custom_scope/1,
  42. three_nodes_multi_call_default_scope/1,
  43. three_nodes_multi_call_custom_scope/1
  44. ]).
  45. %% internals
  46. -export([
  47. subscriber_loop/2,
  48. recipient_loop/0
  49. ]).
  50. %% include
  51. -include_lib("common_test/include/ct.hrl").
  52. -include_lib("syn/src/syn.hrl").
  53. %% ===================================================================
  54. %% Callbacks
  55. %% ===================================================================
  56. %% -------------------------------------------------------------------
  57. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  58. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  59. %% GroupName = atom()
  60. %% TestCase = atom()
  61. %% Reason = any()
  62. %% -------------------------------------------------------------------
  63. all() ->
  64. [
  65. {group, three_nodes_groups}
  66. ].
  67. %% -------------------------------------------------------------------
  68. %% Function: groups() -> [Group]
  69. %% Group = {GroupName,Properties,GroupsAndTestCases}
  70. %% GroupName = atom()
  71. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  72. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  73. %% TestCase = atom()
  74. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  75. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  76. %% repeat_until_any_ok | repeat_until_any_fail
  77. %% N = integer() | forever
  78. %% -------------------------------------------------------------------
  79. groups() ->
  80. [
  81. {three_nodes_groups, [shuffle], [
  82. three_nodes_discover_default_scope,
  83. three_nodes_discover_custom_scope,
  84. three_nodes_join_leave_and_monitor_default_scope,
  85. three_nodes_join_leave_and_monitor_custom_scope,
  86. three_nodes_cluster_changes,
  87. three_nodes_custom_event_handler_joined_left,
  88. three_nodes_publish_default_scope,
  89. three_nodes_publish_custom_scope,
  90. three_nodes_multi_call_default_scope,
  91. three_nodes_multi_call_custom_scope
  92. ]}
  93. ].
  94. %% -------------------------------------------------------------------
  95. %% Function: init_per_suite(Config0) ->
  96. %% Config1 | {skip,Reason} |
  97. %% {skip_and_save,Reason,Config1}
  98. %% Config0 = Config1 = [tuple()]
  99. %% Reason = any()
  100. %% -------------------------------------------------------------------
  101. init_per_suite(Config) ->
  102. Config.
  103. %% -------------------------------------------------------------------
  104. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  105. %% Config0 = Config1 = [tuple()]
  106. %% -------------------------------------------------------------------
  107. end_per_suite(_Config) ->
  108. ok.
  109. %% -------------------------------------------------------------------
  110. %% Function: init_per_group(GroupName, Config0) ->
  111. %% Config1 | {skip,Reason} |
  112. %% {skip_and_save,Reason,Config1}
  113. %% GroupName = atom()
  114. %% Config0 = Config1 = [tuple()]
  115. %% Reason = any()
  116. %% -------------------------------------------------------------------
  117. init_per_group(three_nodes_groups, Config) ->
  118. %% start slave
  119. {ok, SlaveNode1} = syn_test_suite_helper:start_slave(syn_slave_1),
  120. {ok, SlaveNode2} = syn_test_suite_helper:start_slave(syn_slave_2),
  121. syn_test_suite_helper:connect_node(SlaveNode1),
  122. syn_test_suite_helper:connect_node(SlaveNode2),
  123. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  124. %% wait full cluster
  125. case syn_test_suite_helper:wait_cluster_mesh_connected([node(), SlaveNode1, SlaveNode2]) of
  126. ok ->
  127. %% config
  128. [{slave_node_1, SlaveNode1}, {slave_node_2, SlaveNode2} | Config];
  129. Other ->
  130. ct:pal("*********** Could not get full cluster, skipping"),
  131. end_per_group(three_nodes_groups, Config),
  132. {skip, Other}
  133. end;
  134. init_per_group(_GroupName, Config) ->
  135. Config.
  136. %% -------------------------------------------------------------------
  137. %% Function: end_per_group(GroupName, Config0) ->
  138. %% void() | {save_config,Config1}
  139. %% GroupName = atom()
  140. %% Config0 = Config1 = [tuple()]
  141. %% -------------------------------------------------------------------
  142. end_per_group(three_nodes_groups, Config) ->
  143. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  144. syn_test_suite_helper:connect_node(SlaveNode1),
  145. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  146. syn_test_suite_helper:connect_node(SlaveNode2),
  147. syn_test_suite_helper:clean_after_test(),
  148. syn_test_suite_helper:stop_slave(syn_slave_1),
  149. syn_test_suite_helper:stop_slave(syn_slave_2),
  150. timer:sleep(1000);
  151. end_per_group(_GroupName, _Config) ->
  152. syn_test_suite_helper:clean_after_test().
  153. %% -------------------------------------------------------------------
  154. %% Function: init_per_testcase(TestCase, Config0) ->
  155. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  156. %% TestCase = atom()
  157. %% Config0 = Config1 = [tuple()]
  158. %% Reason = any()
  159. %% -------------------------------------------------------------------
  160. init_per_testcase(TestCase, Config) ->
  161. ct:pal("Starting test: ~p", [TestCase]),
  162. Config.
  163. %% -------------------------------------------------------------------
  164. %% Function: end_per_testcase(TestCase, Config0) ->
  165. %% void() | {save_config,Config1} | {fail,Reason}
  166. %% TestCase = atom()
  167. %% Config0 = Config1 = [tuple()]
  168. %% Reason = any()
  169. %% -------------------------------------------------------------------
  170. end_per_testcase(_, _Config) ->
  171. syn_test_suite_helper:clean_after_test().
  172. %% ===================================================================
  173. %% Tests
  174. %% ===================================================================
  175. three_nodes_discover_default_scope(Config) ->
  176. %% get slaves
  177. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  178. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  179. %% start syn on nodes
  180. ok = syn:start(),
  181. ok = rpc:call(SlaveNode1, syn, start, []),
  182. ok = rpc:call(SlaveNode2, syn, start, []),
  183. %% check
  184. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  185. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  186. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  187. %% simulate full netsplit
  188. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  189. syn_test_suite_helper:disconnect_node(SlaveNode1),
  190. syn_test_suite_helper:disconnect_node(SlaveNode2),
  191. syn_test_suite_helper:assert_cluster(node(), []),
  192. %% check
  193. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, []),
  194. %% reconnect slave 1
  195. syn_test_suite_helper:connect_node(SlaveNode1),
  196. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1]),
  197. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  198. %% check
  199. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1]),
  200. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node()]),
  201. %% reconnect all
  202. syn_test_suite_helper:connect_node(SlaveNode2),
  203. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  204. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  205. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  206. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  207. %% check
  208. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  209. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  210. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  211. %% simulate full netsplit, again
  212. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  213. syn_test_suite_helper:disconnect_node(SlaveNode1),
  214. syn_test_suite_helper:disconnect_node(SlaveNode2),
  215. syn_test_suite_helper:assert_cluster(node(), []),
  216. %% check
  217. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, []),
  218. %% reconnect all, again
  219. syn_test_suite_helper:connect_node(SlaveNode2),
  220. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  221. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  222. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  223. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  224. %% check
  225. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  226. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  227. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  228. %% crash the scope process on local
  229. syn_test_suite_helper:kill_process(syn_registry_default),
  230. syn_test_suite_helper:wait_process_name_ready(syn_registry_default),
  231. %% check, it should have rebuilt after supervisor restarts it
  232. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  233. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  234. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  235. %% crash scopes supervisor on local
  236. syn_test_suite_helper:kill_process(syn_scopes_sup),
  237. syn_test_suite_helper:wait_process_name_ready(syn_registry_default),
  238. %% check
  239. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  240. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  241. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]).
  242. three_nodes_discover_custom_scope(Config) ->
  243. %% get slaves
  244. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  245. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  246. %% start syn on nodes
  247. ok = syn:start(),
  248. ok = rpc:call(SlaveNode1, syn, start, []),
  249. ok = rpc:call(SlaveNode2, syn, start, []),
  250. %% add custom scopes
  251. ok = syn:add_node_to_scope(custom_scope_ab),
  252. ok = syn:add_node_to_scope(custom_scope_all),
  253. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc, custom_scope_all]]),
  254. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc, custom_scope_c, custom_scope_all]]),
  255. %% get_subcluster_nodes should return invalid errors
  256. {'EXIT', {{invalid_scope, custom_abcdef}, _}} = catch syn_registry:get_subcluster_nodes(custom_abcdef),
  257. %% check
  258. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  259. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  260. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  261. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  262. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  263. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  264. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  265. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]),
  266. %% check default
  267. syn_test_suite_helper:assert_groups_scope_subcluster(node(), default, [SlaveNode1, SlaveNode2]),
  268. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, default, [node(), SlaveNode2]),
  269. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, default, [node(), SlaveNode1]),
  270. %% disconnect node 2 (node 1 can still see node 2)
  271. syn_test_suite_helper:disconnect_node(SlaveNode2),
  272. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1]),
  273. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  274. %% check
  275. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  276. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1]),
  277. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  278. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  279. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  280. %% reconnect node 2
  281. syn_test_suite_helper:connect_node(SlaveNode2),
  282. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  283. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  284. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  285. %% check
  286. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  287. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  288. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  289. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  290. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  291. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  292. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  293. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]),
  294. %% crash a scope process on 2
  295. rpc:call(SlaveNode2, syn_test_suite_helper, kill_process, [syn_registry_custom_scope_bc]),
  296. rpc:call(SlaveNode2, syn_test_suite_helper, wait_process_name_ready, [syn_registry_default]),
  297. %% check
  298. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  299. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  300. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  301. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  302. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  303. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  304. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  305. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]),
  306. %% crash scopes supervisor on local
  307. syn_test_suite_helper:kill_process(syn_scopes_sup),
  308. syn_test_suite_helper:wait_process_name_ready(syn_registry_default),
  309. %% check
  310. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_ab, [SlaveNode1]),
  311. syn_test_suite_helper:assert_groups_scope_subcluster(node(), custom_scope_all, [SlaveNode1, SlaveNode2]),
  312. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_ab, [node()]),
  313. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_bc, [SlaveNode2]),
  314. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode1, custom_scope_all, [node(), SlaveNode2]),
  315. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_bc, [SlaveNode1]),
  316. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_c, []),
  317. syn_test_suite_helper:assert_groups_scope_subcluster(SlaveNode2, custom_scope_all, [node(), SlaveNode1]).
  318. three_nodes_join_leave_and_monitor_default_scope(Config) ->
  319. %% get slaves
  320. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  321. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  322. %% start syn on nodes
  323. ok = syn:start(),
  324. ok = rpc:call(SlaveNode1, syn, start, []),
  325. ok = rpc:call(SlaveNode2, syn, start, []),
  326. %% start processes
  327. Pid = syn_test_suite_helper:start_process(),
  328. PidWithMeta = syn_test_suite_helper:start_process(),
  329. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  330. %% check
  331. [] = syn:members({group, "one"}),
  332. [] = rpc:call(SlaveNode1, syn, members, [{group, "one"}]),
  333. [] = rpc:call(SlaveNode2, syn, members, [{group, "one"}]),
  334. false = syn:is_member({group, "one"}, Pid),
  335. false = syn:is_member({group, "one"}, PidWithMeta),
  336. false = syn:is_member({group, "one"}, PidRemoteOn1),
  337. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, Pid]),
  338. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidWithMeta]),
  339. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  340. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, Pid]),
  341. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidWithMeta]),
  342. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  343. [] = syn:members({group, "two"}),
  344. [] = rpc:call(SlaveNode1, syn, members, [{group, "two"}]),
  345. [] = rpc:call(SlaveNode2, syn, members, [{group, "two"}]),
  346. false = syn:is_member({group, "two"}, Pid),
  347. false = syn:is_member({group, "two"}, PidWithMeta),
  348. false = syn:is_member({group, "two"}, PidRemoteOn1),
  349. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, Pid]),
  350. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidWithMeta]),
  351. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  352. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, Pid]),
  353. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidWithMeta]),
  354. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  355. [] = syn:local_members({group, "one"}),
  356. [] = rpc:call(SlaveNode1, syn, local_members, [{group, "one"}]),
  357. [] = rpc:call(SlaveNode2, syn, local_members, [{group, "one"}]),
  358. false = syn:is_local_member({group, "one"}, Pid),
  359. false = syn:is_local_member({group, "one"}, PidWithMeta),
  360. false = syn:is_local_member({group, "one"}, PidRemoteOn1),
  361. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, Pid]),
  362. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  363. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  364. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, Pid]),
  365. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  366. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  367. [] = syn:local_members({group, "two"}),
  368. [] = rpc:call(SlaveNode1, syn, local_members, [{group, "two"}]),
  369. [] = rpc:call(SlaveNode2, syn, local_members, [{group, "two"}]),
  370. false = syn:is_local_member({group, "two"}, Pid),
  371. false = syn:is_local_member({group, "two"}, PidWithMeta),
  372. false = syn:is_local_member({group, "two"}, PidRemoteOn1),
  373. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, Pid]),
  374. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  375. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  376. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, Pid]),
  377. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  378. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  379. 0 = syn:groups_count(default),
  380. 0 = syn:groups_count(default, node()),
  381. 0 = syn:groups_count(default, SlaveNode1),
  382. 0 = syn:groups_count(default, SlaveNode2),
  383. %% join
  384. ok = syn:join({group, "one"}, Pid),
  385. ok = syn:join({group, "one"}, PidWithMeta, <<"with meta">>),
  386. ok = syn:join({group, "one"}, PidRemoteOn1),
  387. ok = syn:join({group, "two"}, Pid),
  388. ok = syn:join({group, "two"}, PidWithMeta, "with-meta-2"),
  389. %% errors
  390. {error, not_alive} = syn:join({"pid not alive"}, list_to_pid("<0.9999.0>")),
  391. {error, not_in_group} = syn:leave({group, "three"}, Pid),
  392. %% retrieve
  393. syn_test_suite_helper:assert_wait(
  394. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  395. fun() -> lists:sort(syn:members({group, "one"})) end
  396. ),
  397. syn_test_suite_helper:assert_wait(
  398. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  399. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [{group, "one"}])) end
  400. ),
  401. syn_test_suite_helper:assert_wait(
  402. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}, {PidRemoteOn1, undefined}]),
  403. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [{group, "one"}])) end
  404. ),
  405. true = syn:is_member({group, "one"}, Pid),
  406. true = syn:is_member({group, "one"}, PidWithMeta),
  407. true = syn:is_member({group, "one"}, PidRemoteOn1),
  408. true = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, Pid]),
  409. true = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidWithMeta]),
  410. true = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  411. true = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, Pid]),
  412. true = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidWithMeta]),
  413. true = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  414. syn_test_suite_helper:assert_wait(
  415. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  416. fun() -> lists:sort(syn:local_members({group, "one"})) end
  417. ),
  418. syn_test_suite_helper:assert_wait(
  419. [{PidRemoteOn1, undefined}],
  420. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [{group, "one"}])) end
  421. ),
  422. syn_test_suite_helper:assert_wait(
  423. [],
  424. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [{group, "one"}])) end
  425. ),
  426. true = syn:is_local_member({group, "one"}, Pid),
  427. true = syn:is_local_member({group, "one"}, PidWithMeta),
  428. false = syn:is_local_member({group, "one"}, PidRemoteOn1),
  429. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, Pid]),
  430. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  431. true = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  432. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, Pid]),
  433. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  434. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  435. syn_test_suite_helper:assert_wait(
  436. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  437. fun() -> lists:sort(syn:members({group, "two"})) end
  438. ),
  439. syn_test_suite_helper:assert_wait(
  440. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  441. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [{group, "two"}])) end
  442. ),
  443. syn_test_suite_helper:assert_wait(
  444. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  445. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [{group, "two"}])) end
  446. ),
  447. true = syn:is_member({group, "two"}, Pid),
  448. true = syn:is_member({group, "two"}, PidWithMeta),
  449. false = syn:is_member({group, "two"}, PidRemoteOn1),
  450. true = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, Pid]),
  451. true = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidWithMeta]),
  452. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  453. true = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, Pid]),
  454. true = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidWithMeta]),
  455. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  456. syn_test_suite_helper:assert_wait(
  457. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  458. fun() -> lists:sort(syn:local_members({group, "two"})) end
  459. ),
  460. syn_test_suite_helper:assert_wait(
  461. [],
  462. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [{group, "two"}])) end
  463. ),
  464. syn_test_suite_helper:assert_wait(
  465. [],
  466. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [{group, "two"}])) end
  467. ),
  468. true = syn:is_local_member({group, "two"}, Pid),
  469. true = syn:is_local_member({group, "two"}, PidWithMeta),
  470. false = syn:is_local_member({group, "two"}, PidRemoteOn1),
  471. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, Pid]),
  472. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  473. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  474. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, Pid]),
  475. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  476. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  477. 2 = syn:groups_count(default),
  478. 2 = syn:groups_count(default, node()),
  479. 1 = syn:groups_count(default, SlaveNode1),
  480. 0 = syn:groups_count(default, SlaveNode2),
  481. %% re-join to edit meta
  482. ok = syn:join({group, "one"}, PidWithMeta, <<"with updated meta">>),
  483. ok = rpc:call(SlaveNode2, syn, join, [{group, "one"}, PidRemoteOn1, added_meta]), %% updated on slave 2
  484. %% retrieve
  485. syn_test_suite_helper:assert_wait(
  486. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  487. fun() -> lists:sort(syn:members({group, "one"})) end
  488. ),
  489. syn_test_suite_helper:assert_wait(
  490. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  491. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [{group, "one"}])) end
  492. ),
  493. syn_test_suite_helper:assert_wait(
  494. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}, {PidRemoteOn1, added_meta}]),
  495. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [{group, "one"}])) end
  496. ),
  497. syn_test_suite_helper:assert_wait(
  498. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  499. fun() -> lists:sort(syn:local_members({group, "one"})) end
  500. ),
  501. syn_test_suite_helper:assert_wait(
  502. [{PidRemoteOn1, added_meta}],
  503. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [{group, "one"}])) end
  504. ),
  505. syn_test_suite_helper:assert_wait(
  506. [],
  507. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [{group, "one"}])) end
  508. ),
  509. syn_test_suite_helper:assert_wait(
  510. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  511. fun() -> lists:sort(syn:members({group, "two"})) end
  512. ),
  513. syn_test_suite_helper:assert_wait(
  514. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  515. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [{group, "two"}])) end
  516. ),
  517. syn_test_suite_helper:assert_wait(
  518. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  519. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [{group, "two"}])) end
  520. ),
  521. syn_test_suite_helper:assert_wait(
  522. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  523. fun() -> lists:sort(syn:local_members({group, "two"})) end
  524. ),
  525. syn_test_suite_helper:assert_wait(
  526. [],
  527. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [{group, "two"}])) end
  528. ),
  529. syn_test_suite_helper:assert_wait(
  530. [],
  531. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [{group, "two"}])) end
  532. ),
  533. 2 = syn:groups_count(default),
  534. 2 = syn:groups_count(default, node()),
  535. 1 = syn:groups_count(default, SlaveNode1),
  536. 0 = syn:groups_count(default, SlaveNode2),
  537. %% crash scope process to ensure that monitors get recreated
  538. exit(whereis(syn_groups_default), kill),
  539. syn_test_suite_helper:wait_process_name_ready(syn_groups_default),
  540. %% kill process
  541. syn_test_suite_helper:kill_process(Pid),
  542. syn_test_suite_helper:kill_process(PidRemoteOn1),
  543. %% leave
  544. ok = syn:leave({group, "one"}, PidWithMeta),
  545. %% retrieve
  546. syn_test_suite_helper:assert_wait(
  547. [],
  548. fun() -> lists:sort(syn:members({group, "one"})) end
  549. ),
  550. syn_test_suite_helper:assert_wait(
  551. [],
  552. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [{group, "one"}])) end
  553. ),
  554. syn_test_suite_helper:assert_wait(
  555. [],
  556. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [{group, "one"}])) end
  557. ),
  558. false = syn:is_member({group, "one"}, Pid),
  559. false = syn:is_member({group, "one"}, PidWithMeta),
  560. false = syn:is_member({group, "one"}, PidRemoteOn1),
  561. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, Pid]),
  562. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidWithMeta]),
  563. false = rpc:call(SlaveNode1, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  564. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, Pid]),
  565. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidWithMeta]),
  566. false = rpc:call(SlaveNode2, syn, is_member, [{group, "one"}, PidRemoteOn1]),
  567. syn_test_suite_helper:assert_wait(
  568. [],
  569. fun() -> lists:sort(syn:local_members({group, "one"})) end
  570. ),
  571. syn_test_suite_helper:assert_wait(
  572. [],
  573. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [{group, "one"}])) end
  574. ),
  575. syn_test_suite_helper:assert_wait(
  576. [],
  577. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [{group, "one"}])) end
  578. ),
  579. false = syn:is_local_member({group, "one"}, Pid),
  580. false = syn:is_local_member({group, "one"}, PidWithMeta),
  581. false = syn:is_local_member({group, "one"}, PidRemoteOn1),
  582. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, Pid]),
  583. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  584. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  585. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, Pid]),
  586. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidWithMeta]),
  587. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "one"}, PidRemoteOn1]),
  588. syn_test_suite_helper:assert_wait(
  589. [{PidWithMeta, "with-meta-2"}],
  590. fun() -> lists:sort(syn:members({group, "two"})) end
  591. ),
  592. syn_test_suite_helper:assert_wait(
  593. [{PidWithMeta, "with-meta-2"}],
  594. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [{group, "two"}])) end
  595. ),
  596. syn_test_suite_helper:assert_wait(
  597. [{PidWithMeta, "with-meta-2"}],
  598. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [{group, "two"}])) end
  599. ),
  600. false = syn:is_member({group, "two"}, Pid),
  601. true = syn:is_member({group, "two"}, PidWithMeta),
  602. false = syn:is_member({group, "two"}, PidRemoteOn1),
  603. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, Pid]),
  604. true = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidWithMeta]),
  605. false = rpc:call(SlaveNode1, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  606. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, Pid]),
  607. true = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidWithMeta]),
  608. false = rpc:call(SlaveNode2, syn, is_member, [{group, "two"}, PidRemoteOn1]),
  609. syn_test_suite_helper:assert_wait(
  610. [{PidWithMeta, "with-meta-2"}],
  611. fun() -> lists:sort(syn:local_members({group, "two"})) end
  612. ),
  613. syn_test_suite_helper:assert_wait(
  614. [],
  615. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [{group, "two"}])) end
  616. ),
  617. syn_test_suite_helper:assert_wait(
  618. [],
  619. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [{group, "two"}])) end
  620. ),
  621. false = syn:is_local_member({group, "two"}, Pid),
  622. true = syn:is_local_member({group, "two"}, PidWithMeta),
  623. false = syn:is_local_member({group, "two"}, PidRemoteOn1),
  624. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, Pid]),
  625. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  626. false = rpc:call(SlaveNode1, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  627. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, Pid]),
  628. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidWithMeta]),
  629. false = rpc:call(SlaveNode2, syn, is_local_member, [{group, "two"}, PidRemoteOn1]),
  630. 1 = syn:groups_count(default),
  631. 1 = syn:groups_count(default, node()),
  632. 0 = syn:groups_count(default, SlaveNode1),
  633. 0 = syn:groups_count(default, SlaveNode2),
  634. %% errors
  635. {error, not_in_group} = syn:leave({group, "one"}, PidWithMeta).
  636. three_nodes_join_leave_and_monitor_custom_scope(Config) ->
  637. %% get slaves
  638. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  639. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  640. %% start syn on nodes
  641. ok = syn:start(),
  642. ok = rpc:call(SlaveNode1, syn, start, []),
  643. ok = rpc:call(SlaveNode2, syn, start, []),
  644. %% add custom scopes
  645. ok = syn:add_node_to_scope(custom_scope_ab),
  646. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc]]),
  647. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  648. %% start processes
  649. Pid = syn_test_suite_helper:start_process(),
  650. PidWithMeta = syn_test_suite_helper:start_process(),
  651. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  652. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  653. %% check
  654. [] = syn:members(custom_scope_ab, {group, "one"}),
  655. [] = rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "one"}]),
  656. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "one"}]),
  657. false = syn:is_member(custom_scope_ab, {group, "one"}, Pid),
  658. false = syn:is_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  659. false = syn:is_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  660. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  661. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  662. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  663. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  664. [] = syn:local_members(custom_scope_ab, {group, "one"}),
  665. [] = rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "one"}]),
  666. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "one"}]),
  667. false = syn:is_local_member(custom_scope_ab, {group, "one"}, Pid),
  668. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  669. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  670. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  671. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  672. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  673. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  674. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, {group, "one"}),
  675. [] = rpc:call(SlaveNode1, syn, members, [custom_scope_bc, {group, "one"}]),
  676. [] = rpc:call(SlaveNode2, syn, members, [custom_scope_bc, {group, "one"}]),
  677. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, {group, "one"}),
  678. [] = rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, {group, "one"}]),
  679. [] = rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, {group, "one"}]),
  680. [] = syn:members(custom_scope_ab, {group, "two"}),
  681. [] = rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "two"}]),
  682. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "two"}]),
  683. false = syn:is_member(custom_scope_ab, {group, "two"}, Pid),
  684. false = syn:is_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  685. false = syn:is_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  686. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  687. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  688. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  689. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  690. [] = syn:local_members(custom_scope_ab, {group, "two"}),
  691. [] = rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "two"}]),
  692. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "two"}]),
  693. false = syn:is_local_member(custom_scope_ab, {group, "two"}, Pid),
  694. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  695. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  696. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  697. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  698. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  699. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  700. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, {group, "two"}),
  701. [] = rpc:call(SlaveNode1, syn, members, [custom_scope_bc, {group, "two"}]),
  702. [] = rpc:call(SlaveNode2, syn, members, [custom_scope_bc, {group, "two"}]),
  703. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, {group, "two"}),
  704. [] = rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, {group, "two"}]),
  705. [] = rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, {group, "two"}]),
  706. %% join
  707. ok = syn:join(custom_scope_ab, {group, "one"}, Pid),
  708. ok = syn:join(custom_scope_ab, {group, "one"}, PidWithMeta, <<"with meta">>),
  709. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, {group, "two"}, PidRemoteOn1]),
  710. ok = syn:join(custom_scope_ab, {group, "two"}, Pid),
  711. ok = syn:join(custom_scope_ab, {group, "two"}, PidWithMeta, "with-meta-2"),
  712. %% errors
  713. {error, not_alive} = syn:join({"pid not alive"}, list_to_pid("<0.9999.0>")),
  714. {error, not_in_group} = syn:leave({group, "three"}, Pid),
  715. {'EXIT', {{invalid_scope, custom_scope_ab}, _}} = catch syn:join(custom_scope_ab, {group, "one"}, PidRemoteOn2),
  716. %% retrieve
  717. syn_test_suite_helper:assert_wait(
  718. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  719. fun() -> lists:sort(syn:members(custom_scope_ab, {group, "one"})) end
  720. ),
  721. syn_test_suite_helper:assert_wait(
  722. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  723. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "one"}])) end
  724. ),
  725. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "one"}]),
  726. true = syn:is_member(custom_scope_ab, {group, "one"}, Pid),
  727. true = syn:is_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  728. false = syn:is_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  729. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  730. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  731. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  732. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  733. syn_test_suite_helper:assert_wait(
  734. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with meta">>}]),
  735. fun() -> lists:sort(syn:local_members(custom_scope_ab, {group, "one"})) end
  736. ),
  737. syn_test_suite_helper:assert_wait(
  738. [],
  739. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "one"}])) end
  740. ),
  741. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "one"}]),
  742. true = syn:is_local_member(custom_scope_ab, {group, "one"}, Pid),
  743. true = syn:is_local_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  744. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  745. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  746. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  747. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  748. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  749. syn_test_suite_helper:assert_wait(
  750. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  751. fun() -> lists:sort(syn:members(custom_scope_ab, {group, "two"})) end
  752. ),
  753. syn_test_suite_helper:assert_wait(
  754. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  755. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "two"}])) end
  756. ),
  757. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "two"}]),
  758. true = syn:is_member(custom_scope_ab, {group, "two"}, Pid),
  759. true = syn:is_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  760. false = syn:is_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  761. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  762. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  763. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  764. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  765. syn_test_suite_helper:assert_wait(
  766. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  767. fun() -> lists:sort(syn:local_members(custom_scope_ab, {group, "two"})) end
  768. ),
  769. syn_test_suite_helper:assert_wait(
  770. [],
  771. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "two"}])) end
  772. ),
  773. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "two"}]),
  774. true = syn:is_local_member(custom_scope_ab, {group, "two"}, Pid),
  775. true = syn:is_local_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  776. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  777. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  778. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  779. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  780. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  781. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, {group, "two"}),
  782. syn_test_suite_helper:assert_wait(
  783. [{PidRemoteOn1, undefined}],
  784. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_bc, {group, "two"}])) end
  785. ),
  786. syn_test_suite_helper:assert_wait(
  787. [{PidRemoteOn1, undefined}],
  788. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [custom_scope_bc, {group, "two"}])) end
  789. ),
  790. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, {group, "two"}),
  791. syn_test_suite_helper:assert_wait(
  792. [{PidRemoteOn1, undefined}],
  793. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, {group, "two"}])) end
  794. ),
  795. syn_test_suite_helper:assert_wait(
  796. [],
  797. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, {group, "two"}])) end
  798. ),
  799. 2 = syn:groups_count(custom_scope_ab),
  800. 2 = syn:groups_count(custom_scope_ab, node()),
  801. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  802. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  803. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  804. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  805. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  806. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  807. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  808. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  809. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  810. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  811. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  812. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  813. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  814. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  815. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  816. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  817. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  818. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  819. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  820. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  821. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  822. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  823. %% re-join to edit meta
  824. ok = syn:join(custom_scope_ab, {group, "one"}, PidWithMeta, <<"with updated meta">>),
  825. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, {group, "two"}, PidRemoteOn1, added_meta]), %% updated on slave 2
  826. %% retrieve
  827. syn_test_suite_helper:assert_wait(
  828. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  829. fun() -> lists:sort(syn:members(custom_scope_ab, {group, "one"})) end
  830. ),
  831. syn_test_suite_helper:assert_wait(
  832. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  833. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "one"}])) end
  834. ),
  835. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "one"}]),
  836. syn_test_suite_helper:assert_wait(
  837. lists:sort([{Pid, undefined}, {PidWithMeta, <<"with updated meta">>}]),
  838. fun() -> lists:sort(syn:local_members(custom_scope_ab, {group, "one"})) end
  839. ),
  840. syn_test_suite_helper:assert_wait(
  841. [],
  842. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "one"}])) end
  843. ),
  844. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "one"}]),
  845. syn_test_suite_helper:assert_wait(
  846. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  847. fun() -> lists:sort(syn:members(custom_scope_ab, {group, "two"})) end
  848. ),
  849. syn_test_suite_helper:assert_wait(
  850. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  851. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "two"}])) end
  852. ),
  853. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "two"}]),
  854. syn_test_suite_helper:assert_wait(
  855. lists:sort([{Pid, undefined}, {PidWithMeta, "with-meta-2"}]),
  856. fun() -> lists:sort(syn:local_members(custom_scope_ab, {group, "two"})) end
  857. ),
  858. syn_test_suite_helper:assert_wait(
  859. [],
  860. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "two"}])) end
  861. ),
  862. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "two"}]),
  863. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, {group, "two"}),
  864. syn_test_suite_helper:assert_wait(
  865. [{PidRemoteOn1, added_meta}],
  866. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_bc, {group, "two"}])) end
  867. ),
  868. syn_test_suite_helper:assert_wait(
  869. [{PidRemoteOn1, added_meta}],
  870. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [custom_scope_bc, {group, "two"}])) end
  871. ),
  872. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, {group, "two"}),
  873. syn_test_suite_helper:assert_wait(
  874. [{PidRemoteOn1, added_meta}],
  875. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, {group, "two"}])) end
  876. ),
  877. syn_test_suite_helper:assert_wait(
  878. [],
  879. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, {group, "two"}])) end
  880. ),
  881. 2 = syn:groups_count(custom_scope_ab),
  882. 2 = syn:groups_count(custom_scope_ab, node()),
  883. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  884. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  885. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  886. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  887. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  888. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  889. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  890. 2 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  891. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  892. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  893. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  894. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  895. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  896. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  897. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  898. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  899. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  900. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  901. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  902. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  903. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  904. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  905. %% crash scope process to ensure that monitors get recreated
  906. exit(whereis(syn_groups_custom_scope_ab), kill),
  907. syn_test_suite_helper:wait_process_name_ready(syn_groups_custom_scope_ab),
  908. %% kill process
  909. syn_test_suite_helper:kill_process(Pid),
  910. syn_test_suite_helper:kill_process(PidRemoteOn1),
  911. %% leave
  912. ok = syn:leave(custom_scope_ab, {group, "one"}, PidWithMeta),
  913. %% retrieve
  914. syn_test_suite_helper:assert_wait(
  915. [],
  916. fun() -> lists:sort(syn:members(custom_scope_ab, {group, "one"})) end
  917. ),
  918. syn_test_suite_helper:assert_wait(
  919. [],
  920. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "one"}])) end
  921. ),
  922. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "one"}]),
  923. false = syn:is_member(custom_scope_ab, {group, "one"}, Pid),
  924. false = syn:is_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  925. false = syn:is_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  926. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  927. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  928. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  929. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "one"}, Pid]),
  930. syn_test_suite_helper:assert_wait(
  931. [],
  932. fun() -> lists:sort(syn:local_members(custom_scope_ab, {group, "one"})) end
  933. ),
  934. syn_test_suite_helper:assert_wait(
  935. [],
  936. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "one"}])) end
  937. ),
  938. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "one"}]),
  939. false = syn:is_local_member(custom_scope_ab, {group, "one"}, Pid),
  940. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidWithMeta),
  941. false = syn:is_local_member(custom_scope_ab, {group, "one"}, PidRemoteOn1),
  942. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  943. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidWithMeta]),
  944. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "one"}, PidRemoteOn1]),
  945. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "one"}, Pid]),
  946. syn_test_suite_helper:assert_wait(
  947. [{PidWithMeta, "with-meta-2"}],
  948. fun() -> lists:sort(syn:members(custom_scope_ab, {group, "two"})) end
  949. ),
  950. syn_test_suite_helper:assert_wait(
  951. [{PidWithMeta, "with-meta-2"}],
  952. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_ab, {group, "two"}])) end
  953. ),
  954. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, members, [custom_scope_ab, {group, "two"}]),
  955. false = syn:is_member(custom_scope_ab, {group, "two"}, Pid),
  956. true = syn:is_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  957. false = syn:is_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  958. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  959. true = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  960. false = rpc:call(SlaveNode1, syn, is_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  961. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_member, [custom_scope_ab, {group, "two"}, Pid]),
  962. syn_test_suite_helper:assert_wait(
  963. [{PidWithMeta, "with-meta-2"}],
  964. fun() -> lists:sort(syn:local_members(custom_scope_ab, {group, "two"})) end
  965. ),
  966. syn_test_suite_helper:assert_wait(
  967. [],
  968. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_ab, {group, "two"}])) end
  969. ),
  970. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, local_members, [custom_scope_ab, {group, "two"}]),
  971. false = syn:is_local_member(custom_scope_ab, {group, "two"}, Pid),
  972. true = syn:is_local_member(custom_scope_ab, {group, "two"}, PidWithMeta),
  973. false = syn:is_local_member(custom_scope_ab, {group, "two"}, PidRemoteOn1),
  974. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  975. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidWithMeta]),
  976. false = rpc:call(SlaveNode1, syn, is_local_member, [custom_scope_ab, {group, "two"}, PidRemoteOn1]),
  977. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, is_local_member, [custom_scope_ab, {group, "two"}, Pid]),
  978. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, {group, "two"}),
  979. syn_test_suite_helper:assert_wait(
  980. [],
  981. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_bc, {group, "two"}])) end
  982. ),
  983. syn_test_suite_helper:assert_wait(
  984. [], fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [custom_scope_bc, {group, "two"}])) end
  985. ),
  986. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, {group, "two"}),
  987. syn_test_suite_helper:assert_wait(
  988. [],
  989. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, {group, "two"}])) end
  990. ),
  991. syn_test_suite_helper:assert_wait(
  992. [], fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, {group, "two"}])) end
  993. ),
  994. 1 = syn:groups_count(custom_scope_ab),
  995. 1 = syn:groups_count(custom_scope_ab, node()),
  996. 0 = syn:groups_count(custom_scope_ab, SlaveNode1),
  997. 0 = syn:groups_count(custom_scope_ab, SlaveNode2),
  998. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  999. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1000. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1001. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1002. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab]),
  1003. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, node()]),
  1004. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  1005. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  1006. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1007. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1008. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1009. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1010. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab]),
  1011. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, node()]),
  1012. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode1]),
  1013. {badrpc, {'EXIT', {{invalid_scope, custom_scope_ab}, _}}} = catch rpc:call(SlaveNode2, syn, groups_count, [custom_scope_ab, SlaveNode2]),
  1014. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1015. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1016. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1017. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1018. %% errors
  1019. {error, not_in_group} = syn:leave(custom_scope_ab, {group, "one"}, PidWithMeta).
  1020. three_nodes_cluster_changes(Config) ->
  1021. %% get slaves
  1022. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1023. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1024. %% disconnect 1 from 2
  1025. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1026. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1027. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1028. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1029. %% start syn on 1 and 2, nodes don't know of each other
  1030. ok = rpc:call(SlaveNode1, syn, start, []),
  1031. ok = rpc:call(SlaveNode2, syn, start, []),
  1032. %% add custom scopes
  1033. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_bc]]),
  1034. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  1035. %% start processes
  1036. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  1037. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2),
  1038. %% join
  1039. ok = rpc:call(SlaveNode1, syn, join, [<<"common-group">>, PidRemoteOn1, "meta-1"]),
  1040. ok = rpc:call(SlaveNode2, syn, join, [<<"common-group">>, PidRemoteOn2, "meta-2"]),
  1041. ok = rpc:call(SlaveNode2, syn, join, [<<"group-2">>, PidRemoteOn2, "other-meta"]),
  1042. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, <<"scoped-on-bc">>, PidRemoteOn1, "scoped-meta-1"]),
  1043. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, <<"scoped-on-bc">>, PidRemoteOn2, "scoped-meta-2"]),
  1044. %% form full cluster
  1045. ok = syn:start(),
  1046. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1047. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1048. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1049. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1050. syn_test_suite_helper:wait_process_name_ready(syn_groups_default),
  1051. %% retrieve
  1052. syn_test_suite_helper:assert_wait(
  1053. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1054. fun() -> lists:sort(syn:members(<<"common-group">>)) end
  1055. ),
  1056. syn_test_suite_helper:assert_wait(
  1057. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1058. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [<<"common-group">>])) end
  1059. ),
  1060. syn_test_suite_helper:assert_wait(
  1061. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1062. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [<<"common-group">>])) end
  1063. ),
  1064. syn_test_suite_helper:assert_wait(
  1065. [],
  1066. fun() -> lists:sort(syn:local_members(<<"common-group">>)) end
  1067. ),
  1068. syn_test_suite_helper:assert_wait(
  1069. [{PidRemoteOn1, "meta-1"}],
  1070. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [<<"common-group">>])) end
  1071. ),
  1072. syn_test_suite_helper:assert_wait(
  1073. [{PidRemoteOn2, "meta-2"}],
  1074. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [<<"common-group">>])) end
  1075. ),
  1076. syn_test_suite_helper:assert_wait(
  1077. [{PidRemoteOn2, "other-meta"}],
  1078. fun() -> lists:sort(syn:members(<<"group-2">>)) end
  1079. ),
  1080. syn_test_suite_helper:assert_wait(
  1081. [{PidRemoteOn2, "other-meta"}],
  1082. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [<<"group-2">>])) end
  1083. ),
  1084. syn_test_suite_helper:assert_wait(
  1085. [{PidRemoteOn2, "other-meta"}],
  1086. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [<<"group-2">>])) end
  1087. ),
  1088. syn_test_suite_helper:assert_wait(
  1089. [],
  1090. fun() -> lists:sort(syn:local_members(<<"group-2">>)) end
  1091. ),
  1092. syn_test_suite_helper:assert_wait(
  1093. [],
  1094. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [<<"group-2">>])) end
  1095. ),
  1096. syn_test_suite_helper:assert_wait(
  1097. [{PidRemoteOn2, "other-meta"}],
  1098. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [<<"group-2">>])) end
  1099. ),
  1100. 2 = syn:groups_count(default),
  1101. 0 = syn:groups_count(default, node()),
  1102. 1 = syn:groups_count(default, SlaveNode1),
  1103. 2 = syn:groups_count(default, SlaveNode2),
  1104. 2 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  1105. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  1106. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  1107. 2 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  1108. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1109. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1110. 1 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1111. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1112. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, <<"scoped-on-bc">>),
  1113. syn_test_suite_helper:assert_wait(
  1114. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1115. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1116. ),
  1117. syn_test_suite_helper:assert_wait(
  1118. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1119. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1120. ),
  1121. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1122. syn_test_suite_helper:assert_wait(
  1123. [{PidRemoteOn1, "scoped-meta-1"}],
  1124. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1125. ),
  1126. syn_test_suite_helper:assert_wait(
  1127. [{PidRemoteOn2, "scoped-meta-2"}],
  1128. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1129. ),
  1130. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1131. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1132. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1133. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1134. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1135. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1136. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1137. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1138. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1139. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1140. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1141. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1142. %% partial netsplit (1 cannot see 2)
  1143. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1144. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1145. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1146. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1147. %% retrieve
  1148. syn_test_suite_helper:assert_wait(
  1149. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1150. fun() -> lists:sort(syn:members(<<"common-group">>)) end
  1151. ),
  1152. syn_test_suite_helper:assert_wait(
  1153. [{PidRemoteOn1, "meta-1"}],
  1154. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [<<"common-group">>])) end
  1155. ),
  1156. syn_test_suite_helper:assert_wait(
  1157. [{PidRemoteOn2, "meta-2"}],
  1158. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [<<"common-group">>])) end
  1159. ),
  1160. syn_test_suite_helper:assert_wait(
  1161. [],
  1162. fun() -> lists:sort(syn:local_members(<<"common-group">>)) end
  1163. ),
  1164. syn_test_suite_helper:assert_wait(
  1165. [{PidRemoteOn1, "meta-1"}],
  1166. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [<<"common-group">>])) end
  1167. ),
  1168. syn_test_suite_helper:assert_wait(
  1169. [{PidRemoteOn2, "meta-2"}],
  1170. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [<<"common-group">>])) end
  1171. ),
  1172. syn_test_suite_helper:assert_wait(
  1173. [{PidRemoteOn2, "other-meta"}],
  1174. fun() -> lists:sort(syn:members(<<"group-2">>)) end
  1175. ),
  1176. syn_test_suite_helper:assert_wait(
  1177. [],
  1178. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [<<"group-2">>])) end
  1179. ),
  1180. syn_test_suite_helper:assert_wait(
  1181. [{PidRemoteOn2, "other-meta"}],
  1182. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [<<"group-2">>])) end
  1183. ),
  1184. syn_test_suite_helper:assert_wait(
  1185. [],
  1186. fun() -> lists:sort(syn:local_members(<<"group-2">>)) end
  1187. ),
  1188. syn_test_suite_helper:assert_wait(
  1189. [],
  1190. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [<<"group-2">>])) end
  1191. ),
  1192. syn_test_suite_helper:assert_wait(
  1193. [{PidRemoteOn2, "other-meta"}],
  1194. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [<<"group-2">>])) end
  1195. ),
  1196. 2 = syn:groups_count(default),
  1197. 0 = syn:groups_count(default, node()),
  1198. 1 = syn:groups_count(default, SlaveNode1),
  1199. 2 = syn:groups_count(default, SlaveNode2),
  1200. 1 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  1201. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  1202. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  1203. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  1204. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1205. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1206. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1207. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1208. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, <<"scoped-on-bc">>),
  1209. syn_test_suite_helper:assert_wait(
  1210. [{PidRemoteOn1, "scoped-meta-1"}],
  1211. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1212. ),
  1213. syn_test_suite_helper:assert_wait(
  1214. [{PidRemoteOn2, "scoped-meta-2"}],
  1215. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1216. ),
  1217. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1218. syn_test_suite_helper:assert_wait(
  1219. [{PidRemoteOn1, "scoped-meta-1"}],
  1220. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1221. ),
  1222. syn_test_suite_helper:assert_wait(
  1223. [{PidRemoteOn2, "scoped-meta-2"}],
  1224. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1225. ),
  1226. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1227. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1228. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1229. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1230. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1231. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1232. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1233. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1234. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1235. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1236. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1237. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1238. %% re-join
  1239. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1240. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1241. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1242. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1243. %% retrieve
  1244. syn_test_suite_helper:assert_wait(
  1245. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1246. fun() -> lists:sort(syn:members(<<"common-group">>)) end
  1247. ),
  1248. syn_test_suite_helper:assert_wait(
  1249. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1250. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [<<"common-group">>])) end
  1251. ),
  1252. syn_test_suite_helper:assert_wait(
  1253. lists:sort([{PidRemoteOn1, "meta-1"}, {PidRemoteOn2, "meta-2"}]),
  1254. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [<<"common-group">>])) end
  1255. ),
  1256. syn_test_suite_helper:assert_wait(
  1257. [],
  1258. fun() -> lists:sort(syn:local_members(<<"common-group">>)) end
  1259. ),
  1260. syn_test_suite_helper:assert_wait(
  1261. [{PidRemoteOn1, "meta-1"}],
  1262. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [<<"common-group">>])) end
  1263. ),
  1264. syn_test_suite_helper:assert_wait(
  1265. [{PidRemoteOn2, "meta-2"}],
  1266. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [<<"common-group">>])) end
  1267. ),
  1268. syn_test_suite_helper:assert_wait(
  1269. [{PidRemoteOn2, "other-meta"}],
  1270. fun() -> lists:sort(syn:members(<<"group-2">>)) end
  1271. ),
  1272. syn_test_suite_helper:assert_wait(
  1273. [{PidRemoteOn2, "other-meta"}],
  1274. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [<<"group-2">>])) end
  1275. ),
  1276. syn_test_suite_helper:assert_wait(
  1277. [{PidRemoteOn2, "other-meta"}],
  1278. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [<<"group-2">>])) end
  1279. ),
  1280. syn_test_suite_helper:assert_wait(
  1281. [],
  1282. fun() -> lists:sort(syn:local_members(<<"group-2">>)) end
  1283. ),
  1284. syn_test_suite_helper:assert_wait(
  1285. [],
  1286. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [<<"group-2">>])) end
  1287. ),
  1288. syn_test_suite_helper:assert_wait(
  1289. [{PidRemoteOn2, "other-meta"}],
  1290. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [<<"group-2">>])) end
  1291. ),
  1292. 2 = syn:groups_count(default),
  1293. 0 = syn:groups_count(default, node()),
  1294. 1 = syn:groups_count(default, SlaveNode1),
  1295. 2 = syn:groups_count(default, SlaveNode2),
  1296. 2 = rpc:call(SlaveNode1, syn, groups_count, [default]),
  1297. 0 = rpc:call(SlaveNode1, syn, groups_count, [default, node()]),
  1298. 1 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode1]),
  1299. 2 = rpc:call(SlaveNode1, syn, groups_count, [default, SlaveNode2]),
  1300. 2 = rpc:call(SlaveNode2, syn, groups_count, [default]),
  1301. 0 = rpc:call(SlaveNode2, syn, groups_count, [default, node()]),
  1302. 1 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode1]),
  1303. 2 = rpc:call(SlaveNode2, syn, groups_count, [default, SlaveNode2]),
  1304. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:members(custom_scope_bc, <<"scoped-on-bc">>),
  1305. syn_test_suite_helper:assert_wait(
  1306. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1307. fun() -> lists:sort(rpc:call(SlaveNode1, syn, members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1308. ),
  1309. syn_test_suite_helper:assert_wait(
  1310. lists:sort([{PidRemoteOn1, "scoped-meta-1"}, {PidRemoteOn2, "scoped-meta-2"}]),
  1311. fun() -> lists:sort(rpc:call(SlaveNode2, syn, members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1312. ),
  1313. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:local_members(custom_scope_bc, <<"scoped-on-bc">>),
  1314. syn_test_suite_helper:assert_wait(
  1315. [{PidRemoteOn1, "scoped-meta-1"}],
  1316. fun() -> lists:sort(rpc:call(SlaveNode1, syn, local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1317. ),
  1318. syn_test_suite_helper:assert_wait(
  1319. [{PidRemoteOn2, "scoped-meta-2"}],
  1320. fun() -> lists:sort(rpc:call(SlaveNode2, syn, local_members, [custom_scope_bc, <<"scoped-on-bc">>])) end
  1321. ),
  1322. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc),
  1323. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, node()),
  1324. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode1),
  1325. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:groups_count(custom_scope_bc, SlaveNode2),
  1326. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc]),
  1327. 0 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, node()]),
  1328. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1329. 1 = rpc:call(SlaveNode1, syn, groups_count, [custom_scope_bc, SlaveNode2]),
  1330. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc]),
  1331. 0 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, node()]),
  1332. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode1]),
  1333. 1 = rpc:call(SlaveNode2, syn, groups_count, [custom_scope_bc, SlaveNode2]).
  1334. three_nodes_custom_event_handler_joined_left(Config) ->
  1335. %% get slaves
  1336. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1337. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1338. %% add custom handler for callbacks
  1339. syn:set_event_handler(syn_test_event_handler_callbacks),
  1340. rpc:call(SlaveNode1, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  1341. rpc:call(SlaveNode2, syn, set_event_handler, [syn_test_event_handler_callbacks]),
  1342. %% start syn on nodes
  1343. ok = syn:start(),
  1344. ok = rpc:call(SlaveNode1, syn, start, []),
  1345. ok = rpc:call(SlaveNode2, syn, start, []),
  1346. %% init
  1347. CurrentNode = node(),
  1348. %% start process
  1349. Pid = syn_test_suite_helper:start_process(),
  1350. Pid2 = syn_test_suite_helper:start_process(),
  1351. %% ---> on join
  1352. ok = syn:join("my-group", Pid, {recipient, self(), <<"meta">>}),
  1353. %% check callbacks called
  1354. syn_test_suite_helper:assert_received_messages([
  1355. {on_process_joined, CurrentNode, default, "my-group", Pid, <<"meta">>},
  1356. {on_process_joined, SlaveNode1, default, "my-group", Pid, <<"meta">>},
  1357. {on_process_joined, SlaveNode2, default, "my-group", Pid, <<"meta">>}
  1358. ]),
  1359. syn_test_suite_helper:assert_empty_queue(self()),
  1360. %% join from another node
  1361. ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid2, {recipient, self(), <<"meta-for-2">>}]),
  1362. %% check callbacks called
  1363. syn_test_suite_helper:assert_received_messages([
  1364. {on_process_joined, CurrentNode, default, "my-group", Pid2, <<"meta-for-2">>},
  1365. {on_process_joined, SlaveNode1, default, "my-group", Pid2, <<"meta-for-2">>},
  1366. {on_process_joined, SlaveNode2, default, "my-group", Pid2, <<"meta-for-2">>}
  1367. ]),
  1368. syn_test_suite_helper:assert_empty_queue(self()),
  1369. %% ---> on meta update
  1370. ok = syn:join("my-group", Pid, {recipient, self(), <<"new-meta-0">>}),
  1371. %% check callbacks called
  1372. syn_test_suite_helper:assert_received_messages([
  1373. {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta-0">>},
  1374. {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta-0">>},
  1375. {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta-0">>}
  1376. ]),
  1377. syn_test_suite_helper:assert_empty_queue(self()),
  1378. %% update meta from another node
  1379. ok = rpc:call(SlaveNode1, syn, join, ["my-group", Pid, {recipient, self(), <<"new-meta">>}]),
  1380. %% check callbacks called
  1381. syn_test_suite_helper:assert_received_messages([
  1382. {on_group_process_updated, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
  1383. {on_group_process_updated, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
  1384. {on_group_process_updated, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
  1385. ]),
  1386. syn_test_suite_helper:assert_empty_queue(self()),
  1387. %% ---> on left
  1388. ok = syn:leave("my-group", Pid),
  1389. %% check callbacks called
  1390. syn_test_suite_helper:assert_received_messages([
  1391. {on_process_left, CurrentNode, default, "my-group", Pid, <<"new-meta">>},
  1392. {on_process_left, SlaveNode1, default, "my-group", Pid, <<"new-meta">>},
  1393. {on_process_left, SlaveNode2, default, "my-group", Pid, <<"new-meta">>}
  1394. ]),
  1395. syn_test_suite_helper:assert_empty_queue(self()),
  1396. %% leave from another node
  1397. ok = rpc:call(SlaveNode1, syn, leave, ["my-group", Pid2]),
  1398. %% check callbacks called
  1399. syn_test_suite_helper:assert_received_messages([
  1400. {on_process_left, CurrentNode, default, "my-group", Pid2, <<"meta-for-2">>},
  1401. {on_process_left, SlaveNode1, default, "my-group", Pid2, <<"meta-for-2">>},
  1402. {on_process_left, SlaveNode2, default, "my-group", Pid2, <<"meta-for-2">>}
  1403. ]),
  1404. syn_test_suite_helper:assert_empty_queue(self()),
  1405. %% clean & check
  1406. syn_test_suite_helper:kill_process(Pid),
  1407. syn_test_suite_helper:assert_empty_queue(self()),
  1408. %% ---> after a netsplit
  1409. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1),
  1410. syn:join(remote_on_1, PidRemoteOn1, {recipient, self(), <<"netsplit">>}),
  1411. %% check callbacks called
  1412. syn_test_suite_helper:assert_received_messages([
  1413. {on_process_joined, CurrentNode, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1414. {on_process_joined, SlaveNode1, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1415. {on_process_joined, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1416. ]),
  1417. syn_test_suite_helper:assert_empty_queue(self()),
  1418. %% partial netsplit (1 cannot see 2)
  1419. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1420. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1421. syn_test_suite_helper:assert_cluster(SlaveNode1, [node()]),
  1422. syn_test_suite_helper:assert_cluster(SlaveNode2, [node()]),
  1423. %% check callbacks called
  1424. syn_test_suite_helper:assert_received_messages([
  1425. {on_process_left, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1426. ]),
  1427. syn_test_suite_helper:assert_empty_queue(self()),
  1428. %% ---> after a re-join
  1429. %% re-join
  1430. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1431. syn_test_suite_helper:assert_cluster(node(), [SlaveNode1, SlaveNode2]),
  1432. syn_test_suite_helper:assert_cluster(SlaveNode1, [node(), SlaveNode2]),
  1433. syn_test_suite_helper:assert_cluster(SlaveNode2, [node(), SlaveNode1]),
  1434. %% check callbacks called
  1435. syn_test_suite_helper:assert_received_messages([
  1436. {on_process_joined, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1437. ]),
  1438. syn_test_suite_helper:assert_empty_queue(self()),
  1439. %% clean
  1440. syn_test_suite_helper:kill_process(PidRemoteOn1),
  1441. %% check callbacks called
  1442. syn_test_suite_helper:assert_received_messages([
  1443. {on_process_left, CurrentNode, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1444. {on_process_left, SlaveNode1, default, remote_on_1, PidRemoteOn1, <<"netsplit">>},
  1445. {on_process_left, SlaveNode2, default, remote_on_1, PidRemoteOn1, <<"netsplit">>}
  1446. ]),
  1447. syn_test_suite_helper:assert_empty_queue(self()),
  1448. %% ---> don't call on monitor rebuild
  1449. %% crash the scope process on local
  1450. syn_test_suite_helper:kill_process(syn_groups_default),
  1451. %% no messages
  1452. syn_test_suite_helper:assert_wait(
  1453. ok,
  1454. fun() -> syn_test_suite_helper:assert_empty_queue(self()) end
  1455. ).
  1456. three_nodes_publish_default_scope(Config) ->
  1457. %% get slaves
  1458. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1459. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1460. %% start syn on nodes
  1461. ok = syn:start(),
  1462. ok = rpc:call(SlaveNode1, syn, start, []),
  1463. ok = rpc:call(SlaveNode2, syn, start, []),
  1464. %% start processes
  1465. TestMessage = test_message,
  1466. TestPid = self(),
  1467. SubscriberLoop = fun() -> subscriber_loop(TestPid, TestMessage) end,
  1468. Pid = syn_test_suite_helper:start_process(SubscriberLoop),
  1469. OtherPid = syn_test_suite_helper:start_process(SubscriberLoop),
  1470. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1, SubscriberLoop),
  1471. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2, SubscriberLoop),
  1472. %% join
  1473. ok = syn:join(<<"subscribers">>, Pid),
  1474. ok = syn:join(<<"ignore">>, OtherPid),
  1475. ok = syn:join(<<"subscribers">>, PidRemoteOn1),
  1476. ok = syn:join(<<"subscribers">>, PidRemoteOn2),
  1477. %% ---> publish
  1478. {ok, 3} = syn:publish(<<"subscribers">>, TestMessage),
  1479. syn_test_suite_helper:assert_received_messages([
  1480. {done, Pid},
  1481. {done, PidRemoteOn1},
  1482. {done, PidRemoteOn2}
  1483. ]),
  1484. syn_test_suite_helper:assert_empty_queue(self()),
  1485. %% non-existant
  1486. {ok, 0} = syn:publish(<<"non-existant">>, TestMessage),
  1487. syn_test_suite_helper:assert_empty_queue(self()),
  1488. %% ---> publish local
  1489. {ok, 1} = syn:local_publish(<<"subscribers">>, test_message),
  1490. syn_test_suite_helper:assert_received_messages([
  1491. {done, Pid}
  1492. ]),
  1493. syn_test_suite_helper:assert_empty_queue(self()),
  1494. %% non-existant
  1495. {ok, 0} = syn:local_publish(<<"non-existant">>, TestMessage),
  1496. syn_test_suite_helper:assert_empty_queue(self()).
  1497. three_nodes_publish_custom_scope(Config) ->
  1498. %% get slaves
  1499. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1500. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1501. %% start syn on nodes
  1502. ok = syn:start(),
  1503. ok = rpc:call(SlaveNode1, syn, start, []),
  1504. ok = rpc:call(SlaveNode2, syn, start, []),
  1505. %% add custom scopes
  1506. ok = syn:add_node_to_scope(custom_scope_ab),
  1507. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc]]),
  1508. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  1509. %% start processes
  1510. TestMessage = test_message,
  1511. TestPid = self(),
  1512. SubscriberLoop = fun() -> subscriber_loop(TestPid, TestMessage) end,
  1513. Pid = syn_test_suite_helper:start_process(SubscriberLoop),
  1514. Pid2 = syn_test_suite_helper:start_process(SubscriberLoop),
  1515. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1, SubscriberLoop),
  1516. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2, SubscriberLoop),
  1517. %% join
  1518. ok = syn:join(custom_scope_ab, <<"subscribers">>, Pid),
  1519. ok = syn:join(custom_scope_ab, <<"subscribers-2">>, Pid2),
  1520. ok = syn:join(custom_scope_ab, <<"subscribers">>, PidRemoteOn1),
  1521. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, <<"subscribers">>, PidRemoteOn1]),
  1522. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, <<"subscribers">>, PidRemoteOn2]),
  1523. %% ---> publish
  1524. {ok, 2} = syn:publish(custom_scope_ab, <<"subscribers">>, TestMessage),
  1525. syn_test_suite_helper:assert_received_messages([
  1526. {done, Pid},
  1527. {done, PidRemoteOn1}
  1528. ]),
  1529. syn_test_suite_helper:assert_empty_queue(self()),
  1530. %% errors
  1531. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:publish(custom_scope_bc, <<"subscribers">>, TestMessage),
  1532. %% on other scope
  1533. {ok, 2} = rpc:call(SlaveNode1, syn, publish, [custom_scope_bc, <<"subscribers">>, TestMessage]),
  1534. syn_test_suite_helper:assert_received_messages([
  1535. {done, PidRemoteOn1},
  1536. {done, PidRemoteOn2}
  1537. ]),
  1538. syn_test_suite_helper:assert_empty_queue(self()),
  1539. %% non-existant
  1540. {ok, 0} = syn:publish(custom_scope_ab, <<"non-existant">>, TestMessage),
  1541. syn_test_suite_helper:assert_empty_queue(self()),
  1542. %% ---> publish local
  1543. {ok, 1} = syn:local_publish(custom_scope_ab, <<"subscribers">>, test_message),
  1544. syn_test_suite_helper:assert_received_messages([
  1545. {done, Pid}
  1546. ]),
  1547. syn_test_suite_helper:assert_empty_queue(self()),
  1548. %% non-existant
  1549. {ok, 0} = syn:local_publish(custom_scope_ab, <<"non-existant">>, TestMessage),
  1550. syn_test_suite_helper:assert_empty_queue(self()).
  1551. three_nodes_multi_call_default_scope(Config) ->
  1552. %% get slaves
  1553. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1554. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1555. %% start syn on nodes
  1556. ok = syn:start(),
  1557. ok = rpc:call(SlaveNode1, syn, start, []),
  1558. ok = rpc:call(SlaveNode2, syn, start, []),
  1559. %% start processes
  1560. RecipientLoopLate = fun() -> timer:sleep(200), recipient_loop() end,
  1561. Pid = syn_test_suite_helper:start_process(fun recipient_loop/0),
  1562. Pid2 = syn_test_suite_helper:start_process(RecipientLoopLate),
  1563. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1, fun recipient_loop/0),
  1564. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2, fun recipient_loop/0),
  1565. %% join
  1566. ok = syn:join(<<"recipients">>, Pid, "meta-1"),
  1567. ok = syn:join(<<"recipients">>, Pid2),
  1568. ok = syn:join(<<"recipients">>, PidRemoteOn1, "meta-on-1"),
  1569. ok = syn:join(<<"recipients">>, PidRemoteOn2, "meta-on-2"),
  1570. %% ---> multi_call
  1571. {Replies, BadReplies} = syn:multi_call(default, <<"recipients">>, test_message, 100),
  1572. RepliesSorted = lists:sort(Replies),
  1573. RepliesSorted = lists:sort([
  1574. {{Pid, "meta-1"}, {reply, test_message, Pid, "meta-1"}},
  1575. {{PidRemoteOn1, "meta-on-1"}, {reply, test_message, PidRemoteOn1, "meta-on-1"}},
  1576. {{PidRemoteOn2, "meta-on-2"}, {reply, test_message, PidRemoteOn2, "meta-on-2"}}
  1577. ]),
  1578. BadReplies = [{Pid2, undefined}],
  1579. %% empty
  1580. {[], []} = syn:multi_call(default, <<"non-existant">>, test_message, 100).
  1581. three_nodes_multi_call_custom_scope(Config) ->
  1582. %% get slaves
  1583. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  1584. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  1585. %% start syn on nodes
  1586. ok = syn:start(),
  1587. ok = rpc:call(SlaveNode1, syn, start, []),
  1588. ok = rpc:call(SlaveNode2, syn, start, []),
  1589. %% add custom scopes
  1590. ok = syn:add_node_to_scope(custom_scope_ab),
  1591. ok = rpc:call(SlaveNode1, syn, add_node_to_scopes, [[custom_scope_ab, custom_scope_bc]]),
  1592. ok = rpc:call(SlaveNode2, syn, add_node_to_scopes, [[custom_scope_bc]]),
  1593. %% start processes
  1594. RecipientLoopLate = fun() -> timer:sleep(200), recipient_loop() end,
  1595. Pid = syn_test_suite_helper:start_process(fun recipient_loop/0),
  1596. Pid2 = syn_test_suite_helper:start_process(RecipientLoopLate),
  1597. PidRemoteOn1 = syn_test_suite_helper:start_process(SlaveNode1, fun recipient_loop/0),
  1598. PidRemoteOn2 = syn_test_suite_helper:start_process(SlaveNode2, fun recipient_loop/0),
  1599. %% join
  1600. ok = syn:join(custom_scope_ab, <<"recipients">>, Pid, "meta-1"),
  1601. ok = syn:join(custom_scope_ab, <<"recipients">>, Pid2),
  1602. ok = syn:join(custom_scope_ab, <<"recipients">>, PidRemoteOn1, "meta-on-ab-1"),
  1603. ok = rpc:call(SlaveNode1, syn, join, [custom_scope_bc, <<"recipients">>, PidRemoteOn1, "meta-on-bc-1"]),
  1604. ok = rpc:call(SlaveNode2, syn, join, [custom_scope_bc, <<"recipients">>, PidRemoteOn2, "meta-on-bc-2"]),
  1605. %% errors
  1606. {'EXIT', {{invalid_scope, custom_scope_bc}, _}} = catch syn:multi_call(custom_scope_bc, <<"recipients">>, test_message, 100),
  1607. %% ---> multi_call
  1608. {RepliesAB, BadRepliesAB} = syn:multi_call(custom_scope_ab, <<"recipients">>, test_message_ab, 100),
  1609. RepliesABSorted = lists:sort(RepliesAB),
  1610. RepliesABSorted = lists:sort([
  1611. {{Pid, "meta-1"}, {reply, test_message_ab, Pid, "meta-1"}},
  1612. {{PidRemoteOn1, "meta-on-ab-1"}, {reply, test_message_ab, PidRemoteOn1, "meta-on-ab-1"}}
  1613. ]),
  1614. BadRepliesAB = [{Pid2, undefined}],
  1615. %% different scope
  1616. {RepliesBC, BadRepliesBC} = rpc:call(SlaveNode1, syn, multi_call, [custom_scope_bc, <<"recipients">>, test_message_bc, 100]),
  1617. RepliesBCSorted = lists:sort(RepliesBC),
  1618. RepliesBCSorted = lists:sort([
  1619. {{PidRemoteOn1, "meta-on-bc-1"}, {reply, test_message_bc, PidRemoteOn1, "meta-on-bc-1"}},
  1620. {{PidRemoteOn2, "meta-on-bc-2"}, {reply, test_message_bc, PidRemoteOn2, "meta-on-bc-2"}}
  1621. ]),
  1622. BadRepliesBC = [].
  1623. %% ===================================================================
  1624. %% Internal
  1625. %% ===================================================================
  1626. subscriber_loop(TestPid, TestMessage) ->
  1627. receive
  1628. TestMessage ->
  1629. TestPid ! {done, self()},
  1630. subscriber_loop(TestPid, TestMessage)
  1631. end.
  1632. recipient_loop() ->
  1633. receive
  1634. {syn_multi_call, TestMessage, CallerPid, Meta} ->
  1635. syn:multi_call_reply(CallerPid, {reply, TestMessage, self(), Meta}),
  1636. recipient_loop()
  1637. end.