syn_groups_SUITE.erl 89 KB

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