syn_groups_SUITE.erl 107 KB

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