@@ -23,6 +23,7 @@ all_tests() ->
2323 [
2424 basics ,
2525 return ,
26+ lost_return_is_resent_on_applied_after_leader_change ,
2627 rabbit_fifo_returns_correlation ,
2728 resends_lost_command ,
2829 returns ,
@@ -56,9 +57,11 @@ init_per_group(_, Config) ->
5657 PrivDir = ? config (priv_dir , Config ),
5758 _ = application :load (ra ),
5859 ok = application :set_env (ra , data_dir , PrivDir ),
60+ application :ensure_all_started (logger ),
5961 application :ensure_all_started (ra ),
6062 application :ensure_all_started (lg ),
6163 SysCfg = ra_system :default_config (),
64+ ra_env :configure_logger (logger ),
6265 ra_system :start (SysCfg #{name => ? RA_SYSTEM }),
6366 Config .
6467
@@ -67,6 +70,7 @@ end_per_group(_, Config) ->
6770 Config .
6871
6972init_per_testcase (TestCase , Config ) ->
73+ ok = logger :set_primary_config (level , all ),
7074 meck :new (rabbit_quorum_queue , [passthrough ]),
7175 meck :expect (rabbit_quorum_queue , handle_tick , fun (_ , _ , _ ) -> ok end ),
7276 meck :expect (rabbit_quorum_queue , cancel_consumer_handler , fun (_ , _ ) -> ok end ),
@@ -162,6 +166,63 @@ return(Config) ->
162166 rabbit_quorum_queue :stop_server (ServerId ),
163167 ok .
164168
169+ lost_return_is_resent_on_applied_after_leader_change (Config ) ->
170+ % % this test handles a case where a combination of a lost/overwritten
171+ % % command and a leader change could result in a client never detecting
172+ % % a new leader and thus never resends whatever command was overwritten
173+ % % in the prior term. The fix is to handle leader changes when processing
174+ % % the {appliekd, _} ra event.
175+ ClusterName = ? config (cluster_name , Config ),
176+ ServerId = ? config (node_id , Config ),
177+ ServerId2 = ? config (node_id2 , Config ),
178+ ServerId3 = ? config (node_id3 , Config ),
179+ Members = [ServerId , ServerId2 , ServerId3 ],
180+
181+ ok = meck :new (ra , [passthrough ]),
182+ ok = start_cluster (ClusterName , Members ),
183+
184+ {ok , _ , Leader } = ra :members (ServerId ),
185+ Followers = lists :delete (Leader , Members ),
186+
187+ F00 = rabbit_fifo_client :init (Members ),
188+ {ok , F0 , []} = rabbit_fifo_client :enqueue (ClusterName , 1 , msg1 , F00 ),
189+ F1 = F0 ,
190+ {_ , _ , F2 } = process_ra_events (receive_ra_events (1 , 0 ), ClusterName , F1 ),
191+ {ok , _ , {_ , _ , MsgId , _ , _ }, F3 } =
192+ rabbit_fifo_client :dequeue (ClusterName , <<" tag" >>, unsettled , F2 ),
193+ {F4 , _ } = rabbit_fifo_client :return (<<" tag" >>, [MsgId ], F3 ),
194+ RaEvt = receive
195+ {ra_event , Leader , {applied , _ } = Evt } ->
196+ Evt
197+ after 5000 ->
198+ ct :fail (" no ra event" )
199+ end ,
200+ NextLeader = hd (Followers ),
201+ timer :sleep (100 ),
202+ ok = ra :transfer_leadership (Leader , NextLeader ),
203+ % % get rid of leader change event
204+ receive
205+ {ra_event , _ , {machine , leader_change }} ->
206+ ok
207+ after 5000 ->
208+ ct :fail (" no machine leader_change event" )
209+ end ,
210+ % % client will "send" to the old leader
211+ meck :expect (ra , pipeline_command , fun (_ , _ , _ , _ ) -> ok end ),
212+ {ok , F5 , []} = rabbit_fifo_client :enqueue (ClusterName , 2 , msg2 , F4 ),
213+ ? assertEqual (2 , rabbit_fifo_client :pending_size (F5 )),
214+ meck :unload (ra ),
215+ % % pass the ra event with the new leader as if the entry was applied
216+ % % by the new leader, not the old
217+ {ok , F6 , _ } = rabbit_fifo_client :handle_ra_event (ClusterName , NextLeader ,
218+ RaEvt , F5 ),
219+ % % this should resend the never applied enqueue
220+ {_ , _ , F7 } = process_ra_events (receive_ra_events (1 , 0 ), ClusterName , F6 ),
221+ ? assertEqual (0 , rabbit_fifo_client :pending_size (F7 )),
222+
223+ flush (),
224+ ok .
225+
165226rabbit_fifo_returns_correlation (Config ) ->
166227 ClusterName = ? config (cluster_name , Config ),
167228 ServerId = ? config (node_id , Config ),
0 commit comments