@@ -1907,6 +1907,161 @@ state_enter_leader(MapState) ->
19071907list_nodes (MapState ) ->
19081908 lists :sort (? MOD :list_nodes (state (MapState ))).
19091909
1910+ evaluate_group_not_found_test (_ ) ->
1911+ State0 = state (),
1912+ Cmd = evaluate_group_command (<<" stream" >>, <<" app" >>, []),
1913+ {State0 , {error , not_found }, []} = ? MOD :apply (Cmd , State0 ),
1914+ ok .
1915+
1916+ evaluate_group_all_connected_no_dead_pids_test (_ ) ->
1917+ Pid0 = new_process (),
1918+ Pid1 = new_process (),
1919+ GId = group_id (),
1920+ Group = grp ([csr (Pid0 , 0 , active ),
1921+ csr (Pid1 , 1 , waiting )]),
1922+ State0 = state (#{GId => Group }),
1923+ Cmd = evaluate_group_command (stream (), name (), []),
1924+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
1925+ assertHasGroup (GId , grp ([csr (Pid0 , 0 , active ),
1926+ csr (Pid1 , 1 , waiting )]),
1927+ Groups1 ),
1928+ assertEmpty (Eff ),
1929+ ok .
1930+
1931+ evaluate_group_remove_dead_pid_consumers_test (_ ) ->
1932+ Pid0 = new_process (),
1933+ Pid1 = new_process (),
1934+ GId = group_id (),
1935+ Group = grp ([csr (Pid0 , 0 , active ),
1936+ csr (Pid1 , 1 , waiting )]),
1937+ State0 = state (#{GId => Group }),
1938+ Cmd = evaluate_group_command (stream (), name (), [Pid0 ]),
1939+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
1940+ assertHasGroup (GId , grp ([csr (Pid1 , 1 , active )]),
1941+ Groups1 ),
1942+ assertSendMessageActivateEffect (Pid1 , 1 , stream (), name (), true , Eff ),
1943+ ok .
1944+
1945+ evaluate_group_remove_disconnected_consumers_test (_ ) ->
1946+ Pid0 = new_process (),
1947+ Pid1 = new_process (),
1948+ Pid2 = new_process (),
1949+ GId = group_id (),
1950+ Group = grp ([csr (Pid0 , 0 , {connected , active }),
1951+ csr (Pid1 , 1 , {disconnected , waiting }),
1952+ csr (Pid2 , 2 , {connected , waiting })]),
1953+ State0 = state (#{GId => Group }),
1954+ Cmd = evaluate_group_command (stream (), name (), []),
1955+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
1956+ assertHasGroup (GId , grp ([csr (Pid0 , 0 , {connected , active }),
1957+ csr (Pid2 , 2 , {connected , waiting })]),
1958+ Groups1 ),
1959+ assertEmpty (Eff ),
1960+ ok .
1961+
1962+ evaluate_group_remove_presumed_down_consumers_test (_ ) ->
1963+ Pid0 = new_process (),
1964+ Pid1 = new_process (),
1965+ Pid2 = new_process (),
1966+ GId = group_id (),
1967+ Group = grp ([csr (Pid0 , 0 , {connected , waiting }),
1968+ csr (Pid1 , 1 , {presumed_down , active }),
1969+ csr (Pid2 , 2 , {connected , waiting })]),
1970+ State0 = state (#{GId => Group }),
1971+ Cmd = evaluate_group_command (stream (), name (), []),
1972+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
1973+ assertHasGroup (GId , grp ([csr (Pid0 , 0 , {connected , active }),
1974+ csr (Pid2 , 2 , {connected , waiting })]),
1975+ Groups1 ),
1976+ assertSendMessageActivateEffect (Pid0 , 0 , stream (), name (), true , Eff ),
1977+ ok .
1978+
1979+ evaluate_group_mix_dead_and_disconnected_test (_ ) ->
1980+ Pid0 = new_process (),
1981+ Pid1 = new_process (),
1982+ Pid2 = new_process (),
1983+ Pid3 = new_process (),
1984+ GId = group_id (),
1985+ Group = grp ([csr (Pid0 , 0 , {connected , active }),
1986+ csr (Pid1 , 1 , {disconnected , waiting }),
1987+ csr (Pid2 , 2 , {connected , waiting }),
1988+ csr (Pid3 , 3 , {connected , waiting })]),
1989+ State0 = state (#{GId => Group }),
1990+ Cmd = evaluate_group_command (stream (), name (), [Pid2 ]),
1991+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
1992+ assertHasGroup (GId , grp ([csr (Pid0 , 0 , {connected , active }),
1993+ csr (Pid3 , 3 , {connected , waiting })]),
1994+ Groups1 ),
1995+ assertEmpty (Eff ),
1996+ ok .
1997+
1998+ evaluate_group_empty_after_cleanup_test (_ ) ->
1999+ Pid0 = new_process (),
2000+ GId = group_id (),
2001+ Group = grp ([csr (Pid0 , 0 , {disconnected , active })]),
2002+ State0 = state (#{GId => Group }),
2003+ Cmd = evaluate_group_command (stream (), name (), []),
2004+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
2005+ assertEmpty (Groups1 ),
2006+ assertEmpty (Eff ),
2007+ ok .
2008+
2009+ evaluate_group_super_stream_rebalance_test (_ ) ->
2010+ Pid0 = new_process (),
2011+ Pid1 = new_process (),
2012+ Pid2 = new_process (),
2013+ GId = group_id (),
2014+ Group = grp (1 , [csr (Pid0 , 0 , {connected , waiting }),
2015+ csr (Pid1 , 1 , {connected , active }),
2016+ csr (Pid2 , 2 , {connected , waiting })]),
2017+ State0 = state (#{GId => Group }),
2018+ Cmd = evaluate_group_command (stream (), name (), [Pid0 ]),
2019+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
2020+ % % Pid0 removed (dead), 2 consumers left
2021+ % % partition_index=1, 1 % 2 = 1, so Pid2 should be active
2022+ % % current active is Pid1 at index 0, new active should be Pid2 at index 1
2023+ assertHasGroup (GId ,
2024+ grp (1 , [csr (Pid1 , 1 , {connected , deactivating }),
2025+ csr (Pid2 , 2 , {connected , waiting })]),
2026+ Groups1 ),
2027+ assertSendMessageSteppingDownEffect (Pid1 , 1 , stream (), name (), Eff ),
2028+ ok .
2029+
2030+ evaluate_group_super_stream_active_removed_test (_ ) ->
2031+ Pid0 = new_process (),
2032+ Pid1 = new_process (),
2033+ GId = group_id (),
2034+ Group = grp (1 , [csr (Pid0 , 0 , {disconnected , active }),
2035+ csr (Pid1 , 1 , {connected , waiting })]),
2036+ State0 = state (#{GId => Group }),
2037+ Cmd = evaluate_group_command (stream (), name (), []),
2038+ {#? STATE {groups = Groups1 }, ok , Eff } = ? MOD :apply (Cmd , State0 ),
2039+ % % disconnected active removed, only Pid1 left, should become active
2040+ assertHasGroup (GId ,
2041+ grp (1 , [csr (Pid1 , 1 , {connected , active })]),
2042+ Groups1 ),
2043+ assertSendMessageActivateEffect (Pid1 , 1 , stream (), name (), true , Eff ),
2044+ ok .
2045+
2046+ evaluate_group_ensure_monitors_test (_ ) ->
2047+ Pid0 = new_process (),
2048+ Pid1 = new_process (),
2049+ Pid2 = new_process (),
2050+ GId = group_id (),
2051+ Group0 = grp ([csr (Pid0 , 0 , {connected , active }),
2052+ csr (Pid1 , 1 , {disconnected , waiting }),
2053+ csr (Pid2 , 2 , {connected , waiting })]),
2054+ State0 = state (#{GId => Group0 }),
2055+ Cmd = evaluate_group_command (stream (), name (), []),
2056+ {State1 , ok , _ } = ? MOD :apply (Cmd , State0 ),
2057+ {#? STATE {pids_groups = PidsGroups1 }, _ , _ } =
2058+ ? MOD :ensure_monitors (Cmd , State1 , #{}, []),
2059+ assertSize (2 , PidsGroups1 ),
2060+ ? assert (maps :is_key (Pid0 , PidsGroups1 )),
2061+ ? assert (maps :is_key (Pid2 , PidsGroups1 )),
2062+ ? assertNot (maps :is_key (Pid1 , PidsGroups1 )),
2063+ ok .
2064+
19102065start_node (Name ) ->
19112066 {ok , NodePid , Node } = peer :start (#{
19122067 name => Name ,
@@ -2041,6 +2196,12 @@ connection_reconnected_command(Pid) ->
20412196purge_nodes_command (Nodes ) ->
20422197 # command_purge_nodes {nodes = Nodes }.
20432198
2199+ evaluate_group_command (Stream , ConsumerName , DeadPids ) ->
2200+ # command_evaluate_group {vhost = <<" /" >>,
2201+ stream = Stream ,
2202+ consumer_name = ConsumerName ,
2203+ dead_pids = DeadPids }.
2204+
20442205assertContainsCheckConnectionEffect (Pid , Effects ) ->
20452206 assertContainsSendMessageEffect (Pid , {sac , check_connection , #{}}, Effects ).
20462207
0 commit comments