@@ -105,7 +105,9 @@ groups() ->
105105 force_checkpoint ,
106106 policy_repair ,
107107 gh_12635 ,
108- replica_states
108+ replica_states ,
109+ restart_after_queue_reincarnation ,
110+ no_messages_after_queue_reincarnation
109111 ]
110112 ++ all_tests ()},
111113 {cluster_size_5 , [], [start_queue ,
@@ -2795,15 +2797,21 @@ add_member_wrong_type(Config) ->
27952797 [<<" /" >>, SQ , Server , voter , 5000 ])).
27962798
27972799add_member_already_a_member (Config ) ->
2798- [Server | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
2800+ [Server , Server2 | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
27992801 Ch = rabbit_ct_client_helpers :open_channel (Config , Server ),
28002802 QQ = ? config (queue_name , Config ),
28012803 ? assertEqual ({'queue.declare_ok' , QQ , 0 , 0 },
28022804 declare (Ch , QQ , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
2805+ R1 = rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }]),
28032806 % % idempotent by design
28042807 ? assertEqual (ok ,
28052808 rpc :call (Server , rabbit_quorum_queue , add_member ,
2806- [<<" /" >>, QQ , Server , voter , 5000 ])).
2809+ [<<" /" >>, QQ , Server , voter , 5000 ])),
2810+ ? assertEqual (R1 , rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }])),
2811+ ? assertEqual (ok ,
2812+ rpc :call (Server , rabbit_quorum_queue , add_member ,
2813+ [<<" /" >>, QQ , Server2 , voter , 5000 ])),
2814+ ? assertEqual (R1 , rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }])).
28072815
28082816add_member_not_found (Config ) ->
28092817 [Server | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
@@ -4920,6 +4928,140 @@ replica_states(Config) ->
49204928 end
49214929 end , Result2 ).
49224930
4931+ % Testcase motivated by : https://github.com/rabbitmq/rabbitmq-server/discussions/13131
4932+ restart_after_queue_reincarnation (Config ) ->
4933+ [S1 , S2 , S3 ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
4934+ Ch = rabbit_ct_client_helpers :open_channel (Config , S1 ),
4935+ QName = <<" QQ" >>,
4936+
4937+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4938+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4939+
4940+ [Q ] = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , list , []),
4941+ VHost = amqqueue :get_vhost (Q ),
4942+
4943+ MessagesPublished = 1000 ,
4944+ publish_many (Ch , QName , MessagesPublished ),
4945+
4946+ % % Trigger a snapshot by purging the queue.
4947+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_queue_type , purge , [Q ]),
4948+
4949+ % % Stop S3
4950+ rabbit_ct_broker_helpers :mark_as_being_drained (Config , S3 ),
4951+ ? assertEqual (ok , rabbit_control_helper :command (stop_app , S3 )),
4952+
4953+ % % Delete and re-declare queue with the same name.
4954+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , delete , [Q ,false ,false ,<<" dummy_user" >>]),
4955+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4956+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4957+
4958+ % Now S3 should have the old queue state, and S1 and S2 a new one.
4959+ St1 = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_quorum_queue , status , [VHost , QName ]),
4960+ Status0 = [{proplists :get_value (<<" Node Name" >>, S ), S } || S <- St1 ],
4961+ S3_Status1 = proplists :get_value (S3 , Status0 ),
4962+ Others_Status1 = [V || {_K , V } <- proplists :delete (S3 , Status0 )],
4963+
4964+ S3_LastLogIndex = proplists :get_value (<<" Last Log Index" >>, S3_Status1 ),
4965+ S3_LastWritten = proplists :get_value (<<" Last Written" >>, S3_Status1 ),
4966+ S3_LastApplied = proplists :get_value (<<" Last Applied" >>, S3_Status1 ),
4967+ S3_CommitIndex = proplists :get_value (<<" Commit Index" >>, S3_Status1 ),
4968+ S3_Term = proplists :get_value (<<" Term" >>, S3_Status1 ),
4969+
4970+ ? assertEqual (noproc , proplists :get_value (<<" Raft State" >>, S3_Status1 )),
4971+ ? assertEqual (unknown , proplists :get_value (<<" Membership" >>, S3_Status1 )),
4972+ [begin
4973+ ? assert (S3_LastLogIndex > proplists :get_value (<<" Last Log Index" >>, O )),
4974+ ? assert (S3_LastWritten > proplists :get_value (<<" Last Written" >>, O )),
4975+ ? assert (S3_LastApplied > proplists :get_value (<<" Last Applied" >>, O )),
4976+ ? assert (S3_CommitIndex > proplists :get_value (<<" Commit Index" >>, O )),
4977+ ? assertEqual (S3_Term , proplists :get_value (<<" Term" >>, O ))
4978+ end || O <- Others_Status1 ],
4979+
4980+ % % Bumping term in online nodes
4981+ rabbit_ct_broker_helpers :rpc (Config , 1 , rabbit_quorum_queue , transfer_leadership , [Q , S2 ]),
4982+
4983+ % % Restart S3
4984+ ? assertEqual (ok , rabbit_control_helper :command (start_app , S3 )),
4985+
4986+ timer :sleep (1000 ),
4987+
4988+ % % Now all three nodes should have the new state.
4989+ Status2 = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_quorum_queue , status , [VHost , QName ]),
4990+ % They are either leader or follower.
4991+ ? assert (
4992+ lists :all (
4993+ fun (NodeStatus ) ->
4994+ NodeRaftState = proplists :get_value (<<" Raft State" >>, NodeStatus ),
4995+ lists :member (NodeRaftState , [leader , follower ])
4996+ end , Status2 )),
4997+ % Remove "Node Name" and "Raft State" from the status.
4998+ Status3 = [NE1 , NE2 , NE3 ]= [
4999+ begin
5000+ R = proplists :delete (<<" Node Name" >>, NodeEntry ),
5001+ proplists :delete (<<" Raft State" >>, R )
5002+ end || NodeEntry <- Status2 ],
5003+ % Check all other properties have same value on all nodes.
5004+ ct :pal (" Status3: ~tp " , [Status3 ]),
5005+ [
5006+ begin
5007+ ? assertEqual (V , proplists :get_value (K , NE2 )),
5008+ ? assertEqual (V , proplists :get_value (K , NE3 ))
5009+ end || {K , V } <- NE1
5010+ ].
5011+
5012+ % Testcase motivated by : https://github.com/rabbitmq/rabbitmq-server/issues/12366
5013+ no_messages_after_queue_reincarnation (Config ) ->
5014+ [S1 , S2 , S3 ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
5015+ Ch = rabbit_ct_client_helpers :open_channel (Config , S1 ),
5016+ QName = <<" QQ" >>,
5017+
5018+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
5019+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
5020+
5021+ [Q ] = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , list , []),
5022+
5023+ publish (Ch , QName , <<" msg1" >>),
5024+ publish (Ch , QName , <<" msg2" >>),
5025+
5026+ % % Stop S3
5027+ rabbit_ct_broker_helpers :mark_as_being_drained (Config , S3 ),
5028+ ? assertEqual (ok , rabbit_control_helper :command (stop_app , S3 )),
5029+
5030+ qos (Ch , 1 , false ),
5031+ subscribe (Ch , QName , false , <<" tag0" >>, [], 500 ),
5032+ DeliveryTag = receive
5033+ {# 'basic.deliver' {delivery_tag = DT }, # amqp_msg {}} ->
5034+ receive
5035+ {# 'basic.deliver' {consumer_tag = <<" tag0" >>}, # amqp_msg {}} ->
5036+ ct :fail (" did not expect the second one" )
5037+ after 500 ->
5038+ DT
5039+ end
5040+ after 500 ->
5041+ ct :fail (" Expected some delivery, but got none" )
5042+ end ,
5043+
5044+ % % Delete and re-declare queue with the same name.
5045+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , delete , [Q ,false ,false ,<<" dummy_user" >>]),
5046+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
5047+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
5048+
5049+ % % Bumping term in online nodes
5050+ rabbit_ct_broker_helpers :rpc (Config , 1 , rabbit_quorum_queue , transfer_leadership , [Q , S2 ]),
5051+
5052+ % % Restart S3
5053+ ? assertEqual (ok , rabbit_control_helper :command (start_app , S3 )),
5054+
5055+ ok = amqp_channel :cast (Ch , # 'basic.ack' {delivery_tag = DeliveryTag ,
5056+ multiple = false }),
5057+ % % No message should be delivered after reincarnation
5058+ receive
5059+ {# 'basic.deliver' {consumer_tag = <<" tag0" >>}, # amqp_msg {}} ->
5060+ ct :fail (" Expected no deliveries, but got one" )
5061+ after 500 ->
5062+ ok
5063+ end .
5064+
49235065% %----------------------------------------------------------------------------
49245066
49255067same_elements (L1 , L2 )
@@ -4989,7 +5131,10 @@ consume_empty(Ch, Queue, NoAck) ->
49895131subscribe (Ch , Queue , NoAck ) ->
49905132 subscribe (Ch , Queue , NoAck , <<" ctag" >>, []).
49915133
5134+
49925135subscribe (Ch , Queue , NoAck , Tag , Args ) ->
5136+ subscribe (Ch , Queue , NoAck , Tag , Args , ? TIMEOUT ).
5137+ subscribe (Ch , Queue , NoAck , Tag , Args , Timeout ) ->
49935138 amqp_channel :subscribe (Ch , # 'basic.consume' {queue = Queue ,
49945139 no_ack = NoAck ,
49955140 arguments = Args ,
@@ -4998,7 +5143,7 @@ subscribe(Ch, Queue, NoAck, Tag, Args) ->
49985143 receive
49995144 # 'basic.consume_ok' {consumer_tag = Tag } ->
50005145 ok
5001- after ? TIMEOUT ->
5146+ after Timeout ->
50025147 flush (100 ),
50035148 exit (subscribe_timeout )
50045149 end .
0 commit comments