syn_groups_SUITE.erl 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. %% ==========================================================================================================
  2. %% Syn - A global Process Registry and Process Group manager.
  3. %%
  4. %% The MIT License (MIT)
  5. %%
  6. %% Copyright (c) 2015-2019 Roberto Ostinelli <roberto@ostinelli.net> and Neato Robotics, Inc.
  7. %%
  8. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  9. %% of this software and associated documentation files (the "Software"), to deal
  10. %% in the Software without restriction, including without limitation the rights
  11. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. %% copies of the Software, and to permit persons to whom the Software is
  13. %% furnished to do so, subject to the following conditions:
  14. %%
  15. %% The above copyright notice and this permission notice shall be included in
  16. %% all copies or substantial portions of the Software.
  17. %%
  18. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. %% THE SOFTWARE.
  25. %% ==========================================================================================================
  26. -module(syn_groups_SUITE).
  27. %% callbacks
  28. -export([all/0]).
  29. -export([init_per_suite/1, end_per_suite/1]).
  30. -export([groups/0, init_per_group/2, end_per_group/2]).
  31. -export([init_per_testcase/2, end_per_testcase/2]).
  32. %% tests
  33. -export([
  34. single_node_join_and_monitor/1,
  35. single_node_join_and_leave/1,
  36. single_node_join_errors/1,
  37. single_node_publish/1,
  38. single_node_multicall/1,
  39. single_node_multicall_with_custom_timeout/1,
  40. single_node_callback_on_process_exit/1,
  41. single_node_monitor_after_group_crash/1
  42. ]).
  43. -export([
  44. two_nodes_join_monitor_and_unregister/1,
  45. two_nodes_local_members/1,
  46. two_nodes_publish/1,
  47. two_nodes_local_publish/1,
  48. two_nodes_multicall/1
  49. ]).
  50. -export([
  51. three_nodes_partial_netsplit_consistency/1,
  52. three_nodes_full_netsplit_consistency/1
  53. ]).
  54. %% include
  55. -include_lib("common_test/include/ct.hrl").
  56. %% ===================================================================
  57. %% Callbacks
  58. %% ===================================================================
  59. %% -------------------------------------------------------------------
  60. %% Function: all() -> GroupsAndTestCases | {skip,Reason}
  61. %% GroupsAndTestCases = [{group,GroupName} | TestCase]
  62. %% GroupName = atom()
  63. %% TestCase = atom()
  64. %% Reason = any()
  65. %% -------------------------------------------------------------------
  66. all() ->
  67. [
  68. {group, single_node_groups},
  69. {group, two_nodes_groups},
  70. {group, three_nodes_groups}
  71. ].
  72. %% -------------------------------------------------------------------
  73. %% Function: groups() -> [Group]
  74. %% Group = {GroupName,Properties,GroupsAndTestCases}
  75. %% GroupName = atom()
  76. %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
  77. %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
  78. %% TestCase = atom()
  79. %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
  80. %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
  81. %% repeat_until_any_ok | repeat_until_any_fail
  82. %% N = integer() | forever
  83. %% -------------------------------------------------------------------
  84. groups() ->
  85. [
  86. {single_node_groups, [shuffle], [
  87. single_node_join_and_monitor,
  88. single_node_join_and_leave,
  89. single_node_join_errors,
  90. single_node_publish,
  91. single_node_multicall,
  92. single_node_multicall_with_custom_timeout,
  93. single_node_callback_on_process_exit,
  94. single_node_monitor_after_group_crash
  95. ]},
  96. {two_nodes_groups, [shuffle], [
  97. two_nodes_join_monitor_and_unregister,
  98. two_nodes_local_members,
  99. two_nodes_publish,
  100. two_nodes_local_publish,
  101. two_nodes_multicall
  102. ]},
  103. {three_nodes_groups, [shuffle], [
  104. three_nodes_partial_netsplit_consistency,
  105. three_nodes_full_netsplit_consistency
  106. ]}
  107. ].
  108. %% -------------------------------------------------------------------
  109. %% Function: init_per_suite(Config0) ->
  110. %% Config1 | {skip,Reason} |
  111. %% {skip_and_save,Reason,Config1}
  112. %% Config0 = Config1 = [tuple()]
  113. %% Reason = any()
  114. %% -------------------------------------------------------------------
  115. init_per_suite(Config) ->
  116. Config.
  117. %% -------------------------------------------------------------------
  118. %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
  119. %% Config0 = Config1 = [tuple()]
  120. %% -------------------------------------------------------------------
  121. end_per_suite(_Config) ->
  122. ok.
  123. %% -------------------------------------------------------------------
  124. %% Function: init_per_group(GroupName, Config0) ->
  125. %% Config1 | {skip,Reason} |
  126. %% {skip_and_save,Reason,Config1}
  127. %% GroupName = atom()
  128. %% Config0 = Config1 = [tuple()]
  129. %% Reason = any()
  130. %% -------------------------------------------------------------------
  131. init_per_group(two_nodes_groups, Config) ->
  132. %% start slave
  133. {ok, SlaveNode} = syn_test_suite_helper:start_slave(syn_slave),
  134. %% config
  135. [{slave_node, SlaveNode} | Config];
  136. init_per_group(three_nodes_groups, Config) ->
  137. %% start slave
  138. {ok, SlaveNode1} = syn_test_suite_helper:start_slave(syn_slave_1),
  139. {ok, SlaveNode2} = syn_test_suite_helper:start_slave(syn_slave_2),
  140. %% config
  141. [{slave_node_1, SlaveNode1}, {slave_node_2, SlaveNode2} | Config];
  142. init_per_group(_GroupName, Config) ->
  143. Config.
  144. %% -------------------------------------------------------------------
  145. %% Function: end_per_group(GroupName, Config0) ->
  146. %% void() | {save_config,Config1}
  147. %% GroupName = atom()
  148. %% Config0 = Config1 = [tuple()]
  149. %% -------------------------------------------------------------------
  150. end_per_group(two_nodes_groups, Config) ->
  151. SlaveNode = proplists:get_value(slave_node, Config),
  152. syn_test_suite_helper:connect_node(SlaveNode),
  153. syn_test_suite_helper:clean_after_test(),
  154. syn_test_suite_helper:stop_slave(syn_slave),
  155. timer:sleep(1000);
  156. end_per_group(three_nodes_groups, Config) ->
  157. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  158. syn_test_suite_helper:connect_node(SlaveNode1),
  159. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  160. syn_test_suite_helper:connect_node(SlaveNode2),
  161. syn_test_suite_helper:clean_after_test(),
  162. syn_test_suite_helper:stop_slave(syn_slave_1),
  163. syn_test_suite_helper:stop_slave(syn_slave_2),
  164. timer:sleep(1000);
  165. end_per_group(_GroupName, _Config) ->
  166. syn_test_suite_helper:clean_after_test().
  167. %% -------------------------------------------------------------------
  168. %% Function: init_per_testcase(TestCase, Config0) ->
  169. %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
  170. %% TestCase = atom()
  171. %% Config0 = Config1 = [tuple()]
  172. %% Reason = any()
  173. %% -------------------------------------------------------------------
  174. init_per_testcase(_TestCase, Config) ->
  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. single_node_join_and_monitor(_Config) ->
  189. GroupName = "my group",
  190. %% start
  191. ok = syn:start(),
  192. %% start processes
  193. Pid = syn_test_suite_helper:start_process(),
  194. PidWithMeta = syn_test_suite_helper:start_process(),
  195. PidOther = syn_test_suite_helper:start_process(),
  196. %% retrieve
  197. [] = syn:get_members(GroupName),
  198. [] = syn:get_members(GroupName, with_meta),
  199. false = syn:member(Pid, GroupName),
  200. false = syn:member(PidWithMeta, GroupName),
  201. false = syn:member(PidOther, GroupName),
  202. %% join
  203. ok = syn:join(GroupName, Pid),
  204. ok = syn:join(GroupName, PidWithMeta, {with, meta}),
  205. ok = syn:join("other-group", PidOther),
  206. %% retrieve
  207. true = syn:member(Pid, GroupName),
  208. true = syn:member(PidWithMeta, GroupName),
  209. false = syn:member(PidOther, GroupName),
  210. true = lists:sort([Pid, PidWithMeta]) =:= lists:sort(syn:get_members(GroupName)),
  211. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with, meta}}])
  212. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  213. %% re-join
  214. ok = syn:join(GroupName, PidWithMeta, {with2, meta2}),
  215. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with2, meta2}}])
  216. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  217. %% kill process
  218. syn_test_suite_helper:kill_process(Pid),
  219. syn_test_suite_helper:kill_process(PidWithMeta),
  220. syn_test_suite_helper:kill_process(PidOther),
  221. timer:sleep(100),
  222. %% retrieve
  223. [] = syn:get_members(GroupName),
  224. [] = syn:get_members(GroupName, with_meta),
  225. false = syn:member(Pid, GroupName),
  226. false = syn:member(PidWithMeta, GroupName).
  227. single_node_join_and_leave(_Config) ->
  228. GroupName = "my group",
  229. %% start
  230. ok = syn:start(),
  231. %% start processes
  232. Pid = syn_test_suite_helper:start_process(),
  233. PidWithMeta = syn_test_suite_helper:start_process(),
  234. %% retrieve
  235. [] = syn:get_members(GroupName),
  236. [] = syn:get_members(GroupName, with_meta),
  237. false = syn:member(Pid, GroupName),
  238. false = syn:member(PidWithMeta, GroupName),
  239. %% join
  240. ok = syn:join(GroupName, Pid),
  241. ok = syn:join(GroupName, PidWithMeta, {with, meta}),
  242. %% retrieve
  243. true = syn:member(Pid, GroupName),
  244. true = syn:member(PidWithMeta, GroupName),
  245. true = lists:sort([Pid, PidWithMeta]) =:= lists:sort(syn:get_members(GroupName)),
  246. true = lists:sort([{Pid, undefined}, {PidWithMeta, {with, meta}}])
  247. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  248. %% leave
  249. ok = syn:leave(GroupName, Pid),
  250. ok = syn:leave(GroupName, PidWithMeta),
  251. timer:sleep(100),
  252. %% retrieve
  253. [] = syn:get_members(GroupName),
  254. [] = syn:get_members(GroupName, with_meta),
  255. false = syn:member(Pid, GroupName),
  256. false = syn:member(PidWithMeta, GroupName),
  257. %% kill processes
  258. syn_test_suite_helper:kill_process(Pid),
  259. syn_test_suite_helper:kill_process(PidWithMeta).
  260. single_node_join_errors(_Config) ->
  261. GroupName = "my group",
  262. %% start
  263. ok = syn:start(),
  264. %% start processes
  265. Pid = syn_test_suite_helper:start_process(),
  266. Pid2 = syn_test_suite_helper:start_process(),
  267. %% join
  268. ok = syn:join(GroupName, Pid),
  269. ok = syn:join(GroupName, Pid2),
  270. true = syn:member(Pid, GroupName),
  271. true = syn:member(Pid2, GroupName),
  272. %% leave
  273. ok = syn:leave(GroupName, Pid),
  274. {error, not_in_group} = syn:leave(GroupName, Pid),
  275. %% kill
  276. syn_test_suite_helper:kill_process(Pid2),
  277. timer:sleep(200),
  278. {error, not_in_group} = syn:leave(GroupName, Pid2),
  279. {error, not_alive} = syn:join(GroupName, Pid2),
  280. %% kill processes
  281. syn_test_suite_helper:kill_process(Pid).
  282. single_node_publish(_Config) ->
  283. GroupName = "my group",
  284. Message = {test, message},
  285. %% start
  286. ok = syn:start(),
  287. %% start processes
  288. ResultPid = self(),
  289. F = fun() ->
  290. receive
  291. Message -> ResultPid ! {received, self(), Message}
  292. end
  293. end,
  294. Pid = syn_test_suite_helper:start_process(F),
  295. Pid2 = syn_test_suite_helper:start_process(F),
  296. OtherPid = syn_test_suite_helper:start_process(F),
  297. %% join
  298. ok = syn:join(GroupName, Pid),
  299. ok = syn:join(GroupName, Pid2),
  300. true = syn:member(Pid, GroupName),
  301. true = syn:member(Pid2, GroupName),
  302. %% send
  303. {ok, 2} = syn:publish(GroupName, Message),
  304. %% check
  305. receive
  306. {received, Pid, Message} -> ok
  307. after 2000 ->
  308. ok = published_message_was_not_received_by_pid_1
  309. end,
  310. receive
  311. {received, Pid2, Message} -> ok
  312. after 2000 ->
  313. ok = published_message_was_not_received_by_pid_2
  314. end,
  315. %% kill processes
  316. syn_test_suite_helper:kill_process(Pid),
  317. syn_test_suite_helper:kill_process(Pid2).
  318. single_node_multicall(_Config) ->
  319. GroupName = <<"my group">>,
  320. %% start
  321. ok = syn:start(),
  322. %% start processes
  323. F = fun() ->
  324. receive
  325. {syn_multi_call, RequestorPid, get_pid_name} ->
  326. syn:multi_call_reply(RequestorPid, {pong, self()})
  327. end
  328. end,
  329. Pid1 = syn_test_suite_helper:start_process(F),
  330. Pid2 = syn_test_suite_helper:start_process(F),
  331. PidUnresponsive = syn_test_suite_helper:start_process(),
  332. %% register
  333. ok = syn:join(GroupName, Pid1),
  334. ok = syn:join(GroupName, Pid2),
  335. ok = syn:join(GroupName, PidUnresponsive),
  336. %% call
  337. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name),
  338. %% check responses
  339. true = lists:sort([
  340. {Pid1, {pong, Pid1}},
  341. {Pid2, {pong, Pid2}}
  342. ]) =:= lists:sort(Replies),
  343. [PidUnresponsive] = BadPids,
  344. %% kill processes
  345. syn_test_suite_helper:kill_process(Pid1),
  346. syn_test_suite_helper:kill_process(Pid2),
  347. syn_test_suite_helper:kill_process(PidUnresponsive).
  348. single_node_multicall_with_custom_timeout(_Config) ->
  349. GroupName = <<"my group">>,
  350. %% start
  351. ok = syn:start(),
  352. %% start processes
  353. F1 = fun() ->
  354. receive
  355. {syn_multi_call, RequestorPid, get_pid_name} ->
  356. syn:multi_call_reply(RequestorPid, {pong, self()})
  357. end
  358. end,
  359. Pid1 = syn_test_suite_helper:start_process(F1),
  360. F2 = fun() ->
  361. receive
  362. {syn_multi_call, RequestorPid, get_pid_name} ->
  363. timer:sleep(5000),
  364. syn:multi_call_reply(RequestorPid, {pong, self()})
  365. end
  366. end,
  367. PidTakesLong = syn_test_suite_helper:start_process(F2),
  368. PidUnresponsive = syn_test_suite_helper:start_process(),
  369. %% register
  370. ok = syn:join(GroupName, Pid1),
  371. ok = syn:join(GroupName, PidTakesLong),
  372. ok = syn:join(GroupName, PidUnresponsive),
  373. %% call
  374. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name, 2000),
  375. %% check responses
  376. [{Pid1, {pong, Pid1}}] = Replies,
  377. true = lists:sort([PidTakesLong, PidUnresponsive]) =:= lists:sort(BadPids),
  378. %% kill processes
  379. syn_test_suite_helper:kill_process(Pid1),
  380. syn_test_suite_helper:kill_process(PidTakesLong),
  381. syn_test_suite_helper:kill_process(PidUnresponsive).
  382. single_node_callback_on_process_exit(_Config) ->
  383. %% use custom handler
  384. syn_test_suite_helper:use_custom_handler(),
  385. %% start
  386. ok = syn:start(),
  387. %% start processes
  388. Pid = syn_test_suite_helper:start_process(),
  389. Pid2 = syn_test_suite_helper:start_process(),
  390. %% join
  391. TestPid = self(),
  392. ok = syn:join(group_1, Pid, {pid_group_1, TestPid}),
  393. ok = syn:join(group_2, Pid, {pid_group_2, TestPid}),
  394. ok = syn:join(group_1, Pid2, {pid2, TestPid}),
  395. %% kill 1
  396. syn_test_suite_helper:kill_process(Pid),
  397. receive
  398. {received_event_on, pid_group_1} ->
  399. ok;
  400. {received_event_on, pid2} ->
  401. ok = callback_on_process_exit_was_received_by_pid2
  402. after 1000 ->
  403. ok = callback_on_process_exit_was_not_received_by_pid
  404. end,
  405. receive
  406. {received_event_on, pid_group_2} ->
  407. ok;
  408. {received_event_on, pid2} ->
  409. ok = callback_on_process_exit_was_received_by_pid2
  410. after 1000 ->
  411. ok = callback_on_process_exit_was_not_received_by_pid
  412. end,
  413. %% unregister & kill 2
  414. ok = syn:leave(group_1, Pid2),
  415. syn_test_suite_helper:kill_process(Pid2),
  416. receive
  417. {received_event_on, pid2} ->
  418. ok = callback_on_process_exit_was_received_by_pid2
  419. after 1000 ->
  420. ok
  421. end.
  422. single_node_monitor_after_group_crash(_Config) ->
  423. GroupName = "my group",
  424. %% start
  425. ok = syn:start(),
  426. %% start processes
  427. Pid = syn_test_suite_helper:start_process(),
  428. %% join
  429. ok = syn:join(GroupName, Pid),
  430. %% kill groups
  431. exit(whereis(syn_groups), kill),
  432. timer:sleep(200),
  433. %% retrieve
  434. true = syn:member(Pid, GroupName),
  435. [Pid] = syn:get_members(GroupName),
  436. %% kill process
  437. syn_test_suite_helper:kill_process(Pid),
  438. timer:sleep(200),
  439. %% retrieve
  440. false = syn:member(Pid, GroupName),
  441. [] = syn:get_members(GroupName).
  442. two_nodes_join_monitor_and_unregister(Config) ->
  443. GroupName = "my group",
  444. %% get slave
  445. SlaveNode = proplists:get_value(slave_node, Config),
  446. %% start
  447. ok = syn:start(),
  448. ok = rpc:call(SlaveNode, syn, start, []),
  449. timer:sleep(100),
  450. %% start processes
  451. LocalPid = syn_test_suite_helper:start_process(),
  452. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  453. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  454. OtherPid = syn_test_suite_helper:start_process(),
  455. %% retrieve
  456. [] = syn:get_members("group-1"),
  457. [] = syn:get_members(GroupName),
  458. [] = syn:get_members(GroupName, with_meta),
  459. false = syn:member(LocalPid, GroupName),
  460. false = syn:member(RemotePid, GroupName),
  461. false = syn:member(RemotePidJoinRemote, GroupName),
  462. false = syn:member(OtherPid, GroupName),
  463. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  464. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  465. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  466. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  467. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  468. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  469. %% join
  470. ok = syn:join(GroupName, LocalPid),
  471. ok = syn:join(GroupName, RemotePid, {with_meta}),
  472. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  473. ok = syn:join("other-group", OtherPid),
  474. timer:sleep(200),
  475. %% retrieve local
  476. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote]) =:= lists:sort(syn:get_members(GroupName)),
  477. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  478. =:= lists:sort(syn:get_members(GroupName, with_meta)),
  479. true = syn:member(LocalPid, GroupName),
  480. true = syn:member(RemotePid, GroupName),
  481. true = syn:member(RemotePidJoinRemote, GroupName),
  482. false = syn:member(OtherPid, GroupName),
  483. %% retrieve remote
  484. true = lists:sort([LocalPid, RemotePid, RemotePidJoinRemote])
  485. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName])),
  486. true = lists:sort([{LocalPid, undefined}, {RemotePid, {with_meta}}, {RemotePidJoinRemote, undefined}])
  487. =:= lists:sort(rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta])),
  488. true = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  489. true = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  490. true = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  491. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  492. %% leave & kill
  493. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  494. ok = syn:leave(GroupName, RemotePid),
  495. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  496. syn_test_suite_helper:kill_process(OtherPid),
  497. timer:sleep(200),
  498. %% retrieve
  499. [] = syn:get_members("group-1"),
  500. [] = syn:get_members(GroupName),
  501. [] = syn:get_members(GroupName, with_meta),
  502. false = syn:member(LocalPid, GroupName),
  503. false = syn:member(RemotePid, GroupName),
  504. false = syn:member(RemotePidJoinRemote, GroupName),
  505. false = syn:member(OtherPid, GroupName),
  506. [] = rpc:call(SlaveNode, syn, get_members, [GroupName]),
  507. [] = rpc:call(SlaveNode, syn, get_members, [GroupName, with_meta]),
  508. false = rpc:call(SlaveNode, syn, member, [LocalPid, GroupName]),
  509. false = rpc:call(SlaveNode, syn, member, [RemotePid, GroupName]),
  510. false = rpc:call(SlaveNode, syn, member, [RemotePidJoinRemote, GroupName]),
  511. false = rpc:call(SlaveNode, syn, member, [OtherPid, GroupName]),
  512. %% kill processes
  513. syn_test_suite_helper:kill_process(LocalPid),
  514. syn_test_suite_helper:kill_process(RemotePid).
  515. two_nodes_local_members(Config) ->
  516. GroupName = "my group",
  517. %% get slave
  518. SlaveNode = proplists:get_value(slave_node, Config),
  519. %% start
  520. ok = syn:start(),
  521. ok = rpc:call(SlaveNode, syn, start, []),
  522. timer:sleep(100),
  523. %% start processes
  524. LocalPid = syn_test_suite_helper:start_process(),
  525. RemotePid = syn_test_suite_helper:start_process(SlaveNode),
  526. RemotePidJoinRemote = syn_test_suite_helper:start_process(SlaveNode),
  527. OtherPid = syn_test_suite_helper:start_process(),
  528. %% local members
  529. [] = syn:get_local_members(GroupName),
  530. [] = syn:get_local_members(GroupName, with_meta),
  531. false = syn:local_member(LocalPid, GroupName),
  532. false = syn:local_member(RemotePid, GroupName),
  533. false = syn:local_member(RemotePidJoinRemote, GroupName),
  534. false = syn:local_member(OtherPid, GroupName),
  535. %% remote members
  536. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  537. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]),
  538. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  539. false = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  540. false = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  541. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  542. %% join
  543. ok = syn:join(GroupName, LocalPid),
  544. ok = syn:join(GroupName, RemotePid, {meta, 2}),
  545. ok = rpc:call(SlaveNode, syn, join, [GroupName, RemotePidJoinRemote]),
  546. ok = syn:join({"other-group"}, OtherPid),
  547. timer:sleep(200),
  548. %% local members
  549. [LocalPid] = syn:get_local_members(GroupName),
  550. [{LocalPid, undefined}] = syn:get_local_members(GroupName, with_meta),
  551. [OtherPid] = syn:get_local_members({"other-group"}),
  552. true = syn:local_member(LocalPid, GroupName),
  553. false = syn:local_member(RemotePid, GroupName),
  554. false = syn:local_member(RemotePidJoinRemote, GroupName),
  555. false = syn:local_member(OtherPid, GroupName),
  556. true = syn:local_member(OtherPid, {"other-group"}),
  557. %% remote members
  558. true = lists:sort([RemotePid, RemotePidJoinRemote])
  559. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName])),
  560. true = lists:sort([{RemotePid, {meta, 2}}, {RemotePidJoinRemote, undefined}])
  561. =:= lists:sort(rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta])),
  562. false = rpc:call(SlaveNode, syn, local_member, [LocalPid, GroupName]),
  563. true = rpc:call(SlaveNode, syn, local_member, [RemotePid, GroupName]),
  564. true = rpc:call(SlaveNode, syn, local_member, [RemotePidJoinRemote, GroupName]),
  565. false = rpc:call(SlaveNode, syn, local_member, [OtherPid, GroupName]),
  566. %% leave & kill
  567. ok = rpc:call(SlaveNode, syn, leave, [GroupName, LocalPid]),
  568. ok = syn:leave(GroupName, RemotePid),
  569. syn_test_suite_helper:kill_process(RemotePidJoinRemote),
  570. syn_test_suite_helper:kill_process(OtherPid),
  571. timer:sleep(200),
  572. %% local members
  573. [] = syn:get_local_members(GroupName),
  574. [] = syn:get_local_members(GroupName, with_meta),
  575. %% remote members
  576. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
  577. [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]),
  578. %% kill processes
  579. syn_test_suite_helper:kill_process(LocalPid),
  580. syn_test_suite_helper:kill_process(RemotePid).
  581. two_nodes_publish(Config) ->
  582. GroupName = "my group",
  583. Message = {test, message},
  584. %% get slave
  585. SlaveNode = proplists:get_value(slave_node, Config),
  586. %% start
  587. ok = syn:start(),
  588. ok = rpc:call(SlaveNode, syn, start, []),
  589. timer:sleep(100),
  590. %% start processes
  591. ResultPid = self(),
  592. F = fun() ->
  593. receive
  594. Message -> ResultPid ! {received, self(), Message}
  595. end
  596. end,
  597. LocalPid = syn_test_suite_helper:start_process(F),
  598. LocalPid2 = syn_test_suite_helper:start_process(F),
  599. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  600. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  601. OtherPid = syn_test_suite_helper:start_process(F),
  602. %% join
  603. ok = syn:join(GroupName, LocalPid),
  604. ok = syn:join(GroupName, LocalPid2),
  605. ok = syn:join(GroupName, RemotePid),
  606. ok = syn:join(GroupName, RemotePid2),
  607. timer:sleep(200),
  608. %% send
  609. {ok, 4} = syn:publish(GroupName, Message),
  610. %% check
  611. receive
  612. {received, LocalPid, Message} -> ok
  613. after 2000 ->
  614. ok = published_message_was_not_received_by_local_pid
  615. end,
  616. receive
  617. {received, LocalPid2, Message} -> ok
  618. after 2000 ->
  619. ok = published_message_was_not_received_by_local_pid_2
  620. end,
  621. receive
  622. {received, RemotePid, Message} -> ok
  623. after 2000 ->
  624. ok = published_message_was_not_received_by_remote_pid
  625. end,
  626. receive
  627. {received, RemotePid2, Message} -> ok
  628. after 2000 ->
  629. ok = published_message_was_not_received_by_remote_pid_2
  630. end,
  631. receive
  632. {received, OtherPid, Message} ->
  633. ok = published_message_was_received_by_other_pid
  634. after 250 ->
  635. ok
  636. end,
  637. %% kill processes
  638. syn_test_suite_helper:kill_process(LocalPid),
  639. syn_test_suite_helper:kill_process(LocalPid2),
  640. syn_test_suite_helper:kill_process(RemotePid),
  641. syn_test_suite_helper:kill_process(RemotePid2),
  642. syn_test_suite_helper:kill_process(OtherPid).
  643. two_nodes_local_publish(Config) ->
  644. GroupName = "my group",
  645. Message = {test, message},
  646. %% get slave
  647. SlaveNode = proplists:get_value(slave_node, Config),
  648. %% start
  649. ok = syn:start(),
  650. ok = rpc:call(SlaveNode, syn, start, []),
  651. timer:sleep(100),
  652. %% start processes
  653. ResultPid = self(),
  654. F = fun() ->
  655. receive
  656. Message -> ResultPid ! {received, self(), Message}
  657. end
  658. end,
  659. LocalPid = syn_test_suite_helper:start_process(F),
  660. LocalPid2 = syn_test_suite_helper:start_process(F),
  661. RemotePid = syn_test_suite_helper:start_process(SlaveNode, F),
  662. RemotePid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  663. OtherPid = syn_test_suite_helper:start_process(F),
  664. %% join
  665. ok = syn:join(GroupName, LocalPid),
  666. ok = syn:join(GroupName, LocalPid2),
  667. ok = syn:join(GroupName, RemotePid),
  668. ok = syn:join(GroupName, RemotePid2),
  669. timer:sleep(200),
  670. %% send
  671. {ok, 2} = syn:publish_to_local(GroupName, Message),
  672. %% check
  673. receive
  674. {received, LocalPid, Message} -> ok
  675. after 2000 ->
  676. ok = published_message_was_not_received_by_local_pid
  677. end,
  678. receive
  679. {received, LocalPid2, Message} -> ok
  680. after 2000 ->
  681. ok = published_message_was_not_received_by_local_pid_2
  682. end,
  683. receive
  684. {received, RemotePid, Message} ->
  685. ok = published_message_was_received_by_remote_pid
  686. after 250 ->
  687. ok
  688. end,
  689. receive
  690. {received, RemotePid, Message} ->
  691. ok = published_message_was_received_by_remote_pid_2
  692. after 250 ->
  693. ok
  694. end,
  695. receive
  696. {received, OtherPid, Message} ->
  697. ok = published_message_was_received_by_other_pid
  698. after 250 ->
  699. ok
  700. end,
  701. %% kill processes
  702. syn_test_suite_helper:kill_process(LocalPid),
  703. syn_test_suite_helper:kill_process(LocalPid2),
  704. syn_test_suite_helper:kill_process(RemotePid),
  705. syn_test_suite_helper:kill_process(RemotePid2),
  706. syn_test_suite_helper:kill_process(OtherPid).
  707. two_nodes_multicall(Config) ->
  708. GroupName = <<"my group">>,
  709. %% get slave
  710. SlaveNode = proplists:get_value(slave_node, Config),
  711. %% start
  712. ok = syn:start(),
  713. ok = rpc:call(SlaveNode, syn, start, []),
  714. timer:sleep(100),
  715. %% start processes
  716. F = fun() ->
  717. receive
  718. {syn_multi_call, RequestorPid, get_pid_name} ->
  719. syn:multi_call_reply(RequestorPid, {pong, self()})
  720. end
  721. end,
  722. Pid1 = syn_test_suite_helper:start_process(F),
  723. Pid2 = syn_test_suite_helper:start_process(SlaveNode, F),
  724. PidUnresponsive = syn_test_suite_helper:start_process(),
  725. %% register
  726. ok = syn:join(GroupName, Pid1),
  727. ok = syn:join(GroupName, Pid2),
  728. ok = syn:join(GroupName, PidUnresponsive),
  729. timer:sleep(500),
  730. %% call
  731. {Replies, BadPids} = syn:multi_call(GroupName, get_pid_name),
  732. %% check responses
  733. true = lists:sort([
  734. {Pid1, {pong, Pid1}},
  735. {Pid2, {pong, Pid2}}
  736. ]) =:= lists:sort(Replies),
  737. [PidUnresponsive] = BadPids,
  738. %% kill processes
  739. syn_test_suite_helper:kill_process(Pid1),
  740. syn_test_suite_helper:kill_process(Pid2),
  741. syn_test_suite_helper:kill_process(PidUnresponsive).
  742. three_nodes_partial_netsplit_consistency(Config) ->
  743. GroupName = "my group",
  744. %% get slaves
  745. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  746. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  747. %% start syn on nodes
  748. ok = syn:start(),
  749. ok = rpc:call(SlaveNode1, syn, start, []),
  750. ok = rpc:call(SlaveNode2, syn, start, []),
  751. timer:sleep(100),
  752. %% start processes
  753. Pid0 = syn_test_suite_helper:start_process(),
  754. Pid0Changed = syn_test_suite_helper:start_process(),
  755. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  756. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  757. OtherPid = syn_test_suite_helper:start_process(),
  758. timer:sleep(100),
  759. %% retrieve local
  760. [] = syn:get_members("group-1"),
  761. [] = syn:get_members(GroupName),
  762. [] = syn:get_members(GroupName, with_meta),
  763. false = syn:member(Pid0, GroupName),
  764. false = syn:member(Pid0Changed, GroupName),
  765. false = syn:member(Pid1, GroupName),
  766. false = syn:member(Pid2, GroupName),
  767. %% retrieve slave 1
  768. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  769. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  770. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  771. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  772. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  773. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  774. %% retrieve slave 2
  775. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  776. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  777. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  778. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  779. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  780. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  781. %% join
  782. ok = syn:join(GroupName, Pid0),
  783. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  784. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  785. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  786. ok = syn:join("other-group", OtherPid),
  787. timer:sleep(200),
  788. %% retrieve local
  789. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  790. true = lists:sort([
  791. {Pid0, undefined},
  792. {Pid0Changed, {meta, changed}},
  793. {Pid1, undefined},
  794. {Pid2, {meta, 2}}
  795. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  796. true = syn:member(Pid0, GroupName),
  797. true = syn:member(Pid0Changed, GroupName),
  798. true = syn:member(Pid1, GroupName),
  799. true = syn:member(Pid2, GroupName),
  800. false = syn:member(OtherPid, GroupName),
  801. %% retrieve slave 1
  802. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  803. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  804. true = lists:sort([
  805. {Pid0, undefined},
  806. {Pid0Changed, {meta, changed}},
  807. {Pid1, undefined},
  808. {Pid2, {meta, 2}}
  809. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  810. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  811. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  812. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  813. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  814. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  815. %% retrieve slave 2
  816. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  817. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  818. true = lists:sort([
  819. {Pid0, undefined},
  820. {Pid0Changed, {meta, changed}},
  821. {Pid1, undefined},
  822. {Pid2, {meta, 2}}
  823. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  824. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  825. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  826. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  827. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  828. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  829. %% disconnect slave 2 from main (slave 1 can still see slave 2)
  830. syn_test_suite_helper:disconnect_node(SlaveNode2),
  831. timer:sleep(500),
  832. %% retrieve local
  833. true = lists:sort([Pid0, Pid0Changed, Pid1]) =:= lists:sort(syn:get_members(GroupName)),
  834. true = lists:sort([
  835. {Pid0, undefined},
  836. {Pid0Changed, {meta, changed}},
  837. {Pid1, undefined}
  838. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  839. true = syn:member(Pid0, GroupName),
  840. true = syn:member(Pid0Changed, GroupName),
  841. true = syn:member(Pid1, GroupName),
  842. false = syn:member(Pid2, GroupName),
  843. false = syn:member(OtherPid, GroupName),
  844. %% retrieve slave 1
  845. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  846. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  847. true = lists:sort([
  848. {Pid0, undefined},
  849. {Pid0Changed, {meta, changed}},
  850. {Pid1, undefined},
  851. {Pid2, {meta, 2}}
  852. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  853. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  854. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  855. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  856. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  857. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  858. %% disconnect slave 1
  859. syn_test_suite_helper:disconnect_node(SlaveNode1),
  860. timer:sleep(500),
  861. %% leave 0Changed
  862. ok = syn:leave(GroupName, Pid0Changed),
  863. %% retrieve local
  864. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  865. true = lists:sort([
  866. {Pid0, undefined}
  867. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  868. true = syn:member(Pid0, GroupName),
  869. false = syn:member(Pid0Changed, GroupName),
  870. false = syn:member(Pid1, GroupName),
  871. false = syn:member(Pid2, GroupName),
  872. false = syn:member(OtherPid, GroupName),
  873. %% reconnect all
  874. syn_test_suite_helper:connect_node(SlaveNode1),
  875. syn_test_suite_helper:connect_node(SlaveNode2),
  876. timer:sleep(5000),
  877. %% retrieve local
  878. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  879. true = lists:sort([
  880. {Pid0, undefined},
  881. {Pid1, undefined},
  882. {Pid2, {meta, 2}}
  883. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  884. true = syn:member(Pid0, GroupName),
  885. false = syn:member(Pid0Changed, GroupName),
  886. true = syn:member(Pid1, GroupName),
  887. true = syn:member(Pid2, GroupName),
  888. false = syn:member(OtherPid, GroupName),
  889. %% retrieve slave 1
  890. true = lists:sort([Pid0, Pid1, Pid2])
  891. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  892. true = lists:sort([
  893. {Pid0, undefined},
  894. {Pid1, undefined},
  895. {Pid2, {meta, 2}}
  896. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  897. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  898. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  899. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  900. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  901. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  902. %% retrieve slave 2
  903. true = lists:sort([Pid0, Pid1, Pid2])
  904. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  905. true = lists:sort([
  906. {Pid0, undefined},
  907. {Pid1, undefined},
  908. {Pid2, {meta, 2}}
  909. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  910. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  911. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  912. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  913. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  914. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  915. %% kill processes
  916. syn_test_suite_helper:kill_process(Pid0),
  917. syn_test_suite_helper:kill_process(Pid0Changed),
  918. syn_test_suite_helper:kill_process(Pid1),
  919. syn_test_suite_helper:kill_process(Pid2).
  920. three_nodes_full_netsplit_consistency(Config) ->
  921. GroupName = "my group",
  922. %% get slaves
  923. SlaveNode1 = proplists:get_value(slave_node_1, Config),
  924. SlaveNode2 = proplists:get_value(slave_node_2, Config),
  925. %% start syn on nodes
  926. ok = syn:start(),
  927. ok = rpc:call(SlaveNode1, syn, start, []),
  928. ok = rpc:call(SlaveNode2, syn, start, []),
  929. timer:sleep(100),
  930. %% start processes
  931. Pid0 = syn_test_suite_helper:start_process(),
  932. Pid0Changed = syn_test_suite_helper:start_process(),
  933. Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
  934. Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
  935. OtherPid = syn_test_suite_helper:start_process(),
  936. timer:sleep(100),
  937. %% retrieve local
  938. [] = syn:get_members("group-1"),
  939. [] = syn:get_members(GroupName),
  940. [] = syn:get_members(GroupName, with_meta),
  941. false = syn:member(Pid0, GroupName),
  942. false = syn:member(Pid0Changed, GroupName),
  943. false = syn:member(Pid1, GroupName),
  944. false = syn:member(Pid2, GroupName),
  945. %% retrieve slave 1
  946. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
  947. [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
  948. false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  949. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  950. false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  951. false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  952. %% retrieve slave 2
  953. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
  954. [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
  955. false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  956. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  957. false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  958. false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  959. %% join
  960. ok = syn:join(GroupName, Pid0),
  961. ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
  962. ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
  963. ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
  964. ok = syn:join("other-group", OtherPid),
  965. timer:sleep(200),
  966. %% retrieve local
  967. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  968. true = lists:sort([
  969. {Pid0, undefined},
  970. {Pid0Changed, {meta, changed}},
  971. {Pid1, undefined},
  972. {Pid2, {meta, 2}}
  973. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  974. true = syn:member(Pid0, GroupName),
  975. true = syn:member(Pid0Changed, GroupName),
  976. true = syn:member(Pid1, GroupName),
  977. true = syn:member(Pid2, GroupName),
  978. false = syn:member(OtherPid, GroupName),
  979. %% retrieve slave 1
  980. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  981. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  982. true = lists:sort([
  983. {Pid0, undefined},
  984. {Pid0Changed, {meta, changed}},
  985. {Pid1, undefined},
  986. {Pid2, {meta, 2}}
  987. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  988. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  989. true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  990. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  991. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  992. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  993. %% retrieve slave 2
  994. true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
  995. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  996. true = lists:sort([
  997. {Pid0, undefined},
  998. {Pid0Changed, {meta, changed}},
  999. {Pid1, undefined},
  1000. {Pid2, {meta, 2}}
  1001. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1002. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1003. true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1004. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1005. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1006. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  1007. %% disconnect everyone
  1008. rpc:call(SlaveNode1, syn_test_suite_helper, disconnect_node, [SlaveNode2]),
  1009. syn_test_suite_helper:disconnect_node(SlaveNode1),
  1010. syn_test_suite_helper:disconnect_node(SlaveNode2),
  1011. timer:sleep(1000),
  1012. %% leave 0Changed
  1013. ok = syn:leave(GroupName, Pid0Changed),
  1014. %% retrieve local
  1015. true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
  1016. true = lists:sort([
  1017. {Pid0, undefined}
  1018. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1019. true = syn:member(Pid0, GroupName),
  1020. false = syn:member(Pid0Changed, GroupName),
  1021. false = syn:member(Pid1, GroupName),
  1022. false = syn:member(Pid2, GroupName),
  1023. false = syn:member(OtherPid, GroupName),
  1024. %% reconnect all
  1025. syn_test_suite_helper:connect_node(SlaveNode1),
  1026. syn_test_suite_helper:connect_node(SlaveNode2),
  1027. rpc:call(SlaveNode1, syn_test_suite_helper, connect_node, [SlaveNode2]),
  1028. timer:sleep(1500),
  1029. %% retrieve local
  1030. true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
  1031. true = lists:sort([
  1032. {Pid0, undefined},
  1033. {Pid1, undefined},
  1034. {Pid2, {meta, 2}}
  1035. ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
  1036. true = syn:member(Pid0, GroupName),
  1037. false = syn:member(Pid0Changed, GroupName),
  1038. true = syn:member(Pid1, GroupName),
  1039. true = syn:member(Pid2, GroupName),
  1040. false = syn:member(OtherPid, GroupName),
  1041. %% retrieve slave 1
  1042. true = lists:sort([Pid0, Pid1, Pid2])
  1043. =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
  1044. true = lists:sort([
  1045. {Pid0, undefined},
  1046. {Pid1, undefined},
  1047. {Pid2, {meta, 2}}
  1048. ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
  1049. true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
  1050. false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
  1051. true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
  1052. true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
  1053. false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
  1054. %% retrieve slave 2
  1055. true = lists:sort([Pid0, Pid1, Pid2])
  1056. =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
  1057. true = lists:sort([
  1058. {Pid0, undefined},
  1059. {Pid1, undefined},
  1060. {Pid2, {meta, 2}}
  1061. ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
  1062. true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
  1063. false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
  1064. true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
  1065. true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
  1066. false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
  1067. %% kill processes
  1068. syn_test_suite_helper:kill_process(Pid0),
  1069. syn_test_suite_helper:kill_process(Pid0Changed),
  1070. syn_test_suite_helper:kill_process(Pid1),
  1071. syn_test_suite_helper:kill_process(Pid2).