@@ -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 ,
@@ -2792,15 +2794,21 @@ add_member_wrong_type(Config) ->
27922794 [<<" /" >>, SQ , Server , voter , 5000 ])).
27932795
27942796add_member_already_a_member (Config ) ->
2795- [Server | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
2797+ [Server , Server2 | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
27962798 Ch = rabbit_ct_client_helpers :open_channel (Config , Server ),
27972799 QQ = ? config (queue_name , Config ),
27982800 ? assertEqual ({'queue.declare_ok' , QQ , 0 , 0 },
27992801 declare (Ch , QQ , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
2802+ R1 = rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }]),
28002803 % % idempotent by design
28012804 ? assertEqual (ok ,
28022805 rpc :call (Server , rabbit_quorum_queue , add_member ,
2803- [<<" /" >>, QQ , Server , voter , 5000 ])).
2806+ [<<" /" >>, QQ , Server , voter , 5000 ])),
2807+ ? assertEqual (R1 , rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }])),
2808+ ? assertEqual (ok ,
2809+ rpc :call (Server , rabbit_quorum_queue , add_member ,
2810+ [<<" /" >>, QQ , Server2 , voter , 5000 ])),
2811+ ? assertEqual (R1 , rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }])).
28042812
28052813add_member_not_found (Config ) ->
28062814 [Server | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
@@ -4872,6 +4880,140 @@ replica_states(Config) ->
48724880 end
48734881 end , Result2 ).
48744882
4883+ % Testcase motivated by : https://github.com/rabbitmq/rabbitmq-server/discussions/13131
4884+ restart_after_queue_reincarnation (Config ) ->
4885+ [S1 , S2 , S3 ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
4886+ Ch = rabbit_ct_client_helpers :open_channel (Config , S1 ),
4887+ QName = <<" QQ" >>,
4888+
4889+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4890+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4891+
4892+ [Q ] = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , list , []),
4893+ VHost = amqqueue :get_vhost (Q ),
4894+
4895+ MessagesPublished = 1000 ,
4896+ publish_many (Ch , QName , MessagesPublished ),
4897+
4898+ % % Trigger a snapshot by purging the queue.
4899+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_queue_type , purge , [Q ]),
4900+
4901+ % % Stop S3
4902+ rabbit_ct_broker_helpers :mark_as_being_drained (Config , S3 ),
4903+ ? assertEqual (ok , rabbit_control_helper :command (stop_app , S3 )),
4904+
4905+ % % Delete and re-declare queue with the same name.
4906+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , delete , [Q ,false ,false ,<<" dummy_user" >>]),
4907+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4908+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4909+
4910+ % Now S3 should have the old queue state, and S1 and S2 a new one.
4911+ St1 = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_quorum_queue , status , [VHost , QName ]),
4912+ Status0 = [{proplists :get_value (<<" Node Name" >>, S ), S } || S <- St1 ],
4913+ S3_Status1 = proplists :get_value (S3 , Status0 ),
4914+ Others_Status1 = [V || {_K , V } <- proplists :delete (S3 , Status0 )],
4915+
4916+ S3_LastLogIndex = proplists :get_value (<<" Last Log Index" >>, S3_Status1 ),
4917+ S3_LastWritten = proplists :get_value (<<" Last Written" >>, S3_Status1 ),
4918+ S3_LastApplied = proplists :get_value (<<" Last Applied" >>, S3_Status1 ),
4919+ S3_CommitIndex = proplists :get_value (<<" Commit Index" >>, S3_Status1 ),
4920+ S3_Term = proplists :get_value (<<" Term" >>, S3_Status1 ),
4921+
4922+ ? assertEqual (noproc , proplists :get_value (<<" Raft State" >>, S3_Status1 )),
4923+ ? assertEqual (unknown , proplists :get_value (<<" Membership" >>, S3_Status1 )),
4924+ [begin
4925+ ? assert (S3_LastLogIndex > proplists :get_value (<<" Last Log Index" >>, O )),
4926+ ? assert (S3_LastWritten > proplists :get_value (<<" Last Written" >>, O )),
4927+ ? assert (S3_LastApplied > proplists :get_value (<<" Last Applied" >>, O )),
4928+ ? assert (S3_CommitIndex > proplists :get_value (<<" Commit Index" >>, O )),
4929+ ? assertEqual (S3_Term , proplists :get_value (<<" Term" >>, O ))
4930+ end || O <- Others_Status1 ],
4931+
4932+ % % Bumping term in online nodes
4933+ rabbit_ct_broker_helpers :rpc (Config , 1 , rabbit_quorum_queue , transfer_leadership , [Q , S2 ]),
4934+
4935+ % % Restart S3
4936+ ? assertEqual (ok , rabbit_control_helper :command (start_app , S3 )),
4937+
4938+ timer :sleep (1000 ),
4939+
4940+ % % Now all three nodes should have the new state.
4941+ Status2 = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_quorum_queue , status , [VHost , QName ]),
4942+ % They are either leader or follower.
4943+ ? assert (
4944+ lists :all (
4945+ fun (NodeStatus ) ->
4946+ NodeRaftState = proplists :get_value (<<" Raft State" >>, NodeStatus ),
4947+ lists :member (NodeRaftState , [leader , follower ])
4948+ end , Status2 )),
4949+ % Remove "Node Name" and "Raft State" from the status.
4950+ Status3 = [NE1 , NE2 , NE3 ]= [
4951+ begin
4952+ R = proplists :delete (<<" Node Name" >>, NodeEntry ),
4953+ proplists :delete (<<" Raft State" >>, R )
4954+ end || NodeEntry <- Status2 ],
4955+ % Check all other properties have same value on all nodes.
4956+ ct :pal (" Status3: ~tp " , [Status3 ]),
4957+ [
4958+ begin
4959+ ? assertEqual (V , proplists :get_value (K , NE2 )),
4960+ ? assertEqual (V , proplists :get_value (K , NE3 ))
4961+ end || {K , V } <- NE1
4962+ ].
4963+
4964+ % Testcase motivated by : https://github.com/rabbitmq/rabbitmq-server/issues/12366
4965+ no_messages_after_queue_reincarnation (Config ) ->
4966+ [S1 , S2 , S3 ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
4967+ Ch = rabbit_ct_client_helpers :open_channel (Config , S1 ),
4968+ QName = <<" QQ" >>,
4969+
4970+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4971+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4972+
4973+ [Q ] = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , list , []),
4974+
4975+ publish (Ch , QName , <<" msg1" >>),
4976+ publish (Ch , QName , <<" msg2" >>),
4977+
4978+ % % Stop S3
4979+ rabbit_ct_broker_helpers :mark_as_being_drained (Config , S3 ),
4980+ ? assertEqual (ok , rabbit_control_helper :command (stop_app , S3 )),
4981+
4982+ qos (Ch , 1 , false ),
4983+ subscribe (Ch , QName , false , <<" tag0" >>, [], 500 ),
4984+ DeliveryTag = receive
4985+ {# 'basic.deliver' {delivery_tag = DT }, # amqp_msg {}} ->
4986+ receive
4987+ {# 'basic.deliver' {consumer_tag = <<" tag0" >>}, # amqp_msg {}} ->
4988+ ct :fail (" did not expect the second one" )
4989+ after 500 ->
4990+ DT
4991+ end
4992+ after 500 ->
4993+ ct :fail (" Expected some delivery, but got none" )
4994+ end ,
4995+
4996+ % % Delete and re-declare queue with the same name.
4997+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , delete , [Q ,false ,false ,<<" dummy_user" >>]),
4998+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4999+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
5000+
5001+ % % Bumping term in online nodes
5002+ rabbit_ct_broker_helpers :rpc (Config , 1 , rabbit_quorum_queue , transfer_leadership , [Q , S2 ]),
5003+
5004+ % % Restart S3
5005+ ? assertEqual (ok , rabbit_control_helper :command (start_app , S3 )),
5006+
5007+ ok = amqp_channel :cast (Ch , # 'basic.ack' {delivery_tag = DeliveryTag ,
5008+ multiple = false }),
5009+ % % No message should be delivered after reincarnation
5010+ receive
5011+ {# 'basic.deliver' {consumer_tag = <<" tag0" >>}, # amqp_msg {}} ->
5012+ ct :fail (" Expected no deliveries, but got one" )
5013+ after 500 ->
5014+ ok
5015+ end .
5016+
48755017% %----------------------------------------------------------------------------
48765018
48775019same_elements (L1 , L2 )
@@ -4941,7 +5083,10 @@ consume_empty(Ch, Queue, NoAck) ->
49415083subscribe (Ch , Queue , NoAck ) ->
49425084 subscribe (Ch , Queue , NoAck , <<" ctag" >>, []).
49435085
5086+
49445087subscribe (Ch , Queue , NoAck , Tag , Args ) ->
5088+ subscribe (Ch , Queue , NoAck , Tag , Args , ? TIMEOUT ).
5089+ subscribe (Ch , Queue , NoAck , Tag , Args , Timeout ) ->
49455090 amqp_channel :subscribe (Ch , # 'basic.consume' {queue = Queue ,
49465091 no_ack = NoAck ,
49475092 arguments = Args ,
@@ -4950,7 +5095,7 @@ subscribe(Ch, Queue, NoAck, Tag, Args) ->
49505095 receive
49515096 # 'basic.consume_ok' {consumer_tag = Tag } ->
49525097 ok
4953- after ? TIMEOUT ->
5098+ after Timeout ->
49545099 flush (100 ),
49555100 exit (subscribe_timeout )
49565101 end .
0 commit comments