syn_pg_SUITE.erl 89 KB

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