@@ -105,7 +105,9 @@ groups() ->
105
105
force_checkpoint ,
106
106
policy_repair ,
107
107
gh_12635 ,
108
- replica_states
108
+ replica_states ,
109
+ restart_after_queue_reincarnation ,
110
+ no_messages_after_queue_reincarnation
109
111
]
110
112
++ all_tests ()},
111
113
{cluster_size_5 , [], [start_queue ,
@@ -2802,15 +2804,21 @@ add_member_wrong_type(Config) ->
2802
2804
[<<" /" >>, SQ , Server , voter , 5000 ])).
2803
2805
2804
2806
add_member_already_a_member (Config ) ->
2805
- [Server | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
2807
+ [Server , Server2 | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
2806
2808
Ch = rabbit_ct_client_helpers :open_channel (Config , Server ),
2807
2809
QQ = ? config (queue_name , Config ),
2808
2810
? assertEqual ({'queue.declare_ok' , QQ , 0 , 0 },
2809
2811
declare (Ch , QQ , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
2812
+ R1 = rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }]),
2810
2813
% % idempotent by design
2811
2814
? assertEqual (ok ,
2812
2815
rpc :call (Server , rabbit_quorum_queue , add_member ,
2813
- [<<" /" >>, QQ , Server , voter , 5000 ])).
2816
+ [<<" /" >>, QQ , Server , voter , 5000 ])),
2817
+ ? assertEqual (R1 , rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }])),
2818
+ ? assertEqual (ok ,
2819
+ rpc :call (Server , rabbit_quorum_queue , add_member ,
2820
+ [<<" /" >>, QQ , Server2 , voter , 5000 ])),
2821
+ ? assertEqual (R1 , rpc :call (Server , rabbit_amqqueue , lookup , [{resource , <<" /" >>, queue , QQ }])).
2814
2822
2815
2823
add_member_not_found (Config ) ->
2816
2824
[Server | _ ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
@@ -4880,6 +4888,140 @@ replica_states(Config) ->
4880
4888
end
4881
4889
end , Result2 ).
4882
4890
4891
+ % Testcase motivated by : https://github.com/rabbitmq/rabbitmq-server/discussions/13131
4892
+ restart_after_queue_reincarnation (Config ) ->
4893
+ [S1 , S2 , S3 ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
4894
+ Ch = rabbit_ct_client_helpers :open_channel (Config , S1 ),
4895
+ QName = <<" QQ" >>,
4896
+
4897
+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4898
+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4899
+
4900
+ [Q ] = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , list , []),
4901
+ VHost = amqqueue :get_vhost (Q ),
4902
+
4903
+ MessagesPublished = 1000 ,
4904
+ publish_many (Ch , QName , MessagesPublished ),
4905
+
4906
+ % % Trigger a snapshot by purging the queue.
4907
+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_queue_type , purge , [Q ]),
4908
+
4909
+ % % Stop S3
4910
+ rabbit_ct_broker_helpers :mark_as_being_drained (Config , S3 ),
4911
+ ? assertEqual (ok , rabbit_control_helper :command (stop_app , S3 )),
4912
+
4913
+ % % Delete and re-declare queue with the same name.
4914
+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , delete , [Q ,false ,false ,<<" dummy_user" >>]),
4915
+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4916
+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4917
+
4918
+ % Now S3 should have the old queue state, and S1 and S2 a new one.
4919
+ St1 = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_quorum_queue , status , [VHost , QName ]),
4920
+ Status0 = [{proplists :get_value (<<" Node Name" >>, S ), S } || S <- St1 ],
4921
+ S3_Status1 = proplists :get_value (S3 , Status0 ),
4922
+ Others_Status1 = [V || {_K , V } <- proplists :delete (S3 , Status0 )],
4923
+
4924
+ S3_LastLogIndex = proplists :get_value (<<" Last Log Index" >>, S3_Status1 ),
4925
+ S3_LastWritten = proplists :get_value (<<" Last Written" >>, S3_Status1 ),
4926
+ S3_LastApplied = proplists :get_value (<<" Last Applied" >>, S3_Status1 ),
4927
+ S3_CommitIndex = proplists :get_value (<<" Commit Index" >>, S3_Status1 ),
4928
+ S3_Term = proplists :get_value (<<" Term" >>, S3_Status1 ),
4929
+
4930
+ ? assertEqual (noproc , proplists :get_value (<<" Raft State" >>, S3_Status1 )),
4931
+ ? assertEqual (unknown , proplists :get_value (<<" Membership" >>, S3_Status1 )),
4932
+ [begin
4933
+ ? assert (S3_LastLogIndex > proplists :get_value (<<" Last Log Index" >>, O )),
4934
+ ? assert (S3_LastWritten > proplists :get_value (<<" Last Written" >>, O )),
4935
+ ? assert (S3_LastApplied > proplists :get_value (<<" Last Applied" >>, O )),
4936
+ ? assert (S3_CommitIndex > proplists :get_value (<<" Commit Index" >>, O )),
4937
+ ? assertEqual (S3_Term , proplists :get_value (<<" Term" >>, O ))
4938
+ end || O <- Others_Status1 ],
4939
+
4940
+ % % Bumping term in online nodes
4941
+ rabbit_ct_broker_helpers :rpc (Config , 1 , rabbit_quorum_queue , transfer_leadership , [Q , S2 ]),
4942
+
4943
+ % % Restart S3
4944
+ ? assertEqual (ok , rabbit_control_helper :command (start_app , S3 )),
4945
+
4946
+ timer :sleep (1000 ),
4947
+
4948
+ % % Now all three nodes should have the new state.
4949
+ Status2 = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_quorum_queue , status , [VHost , QName ]),
4950
+ % They are either leader or follower.
4951
+ ? assert (
4952
+ lists :all (
4953
+ fun (NodeStatus ) ->
4954
+ NodeRaftState = proplists :get_value (<<" Raft State" >>, NodeStatus ),
4955
+ lists :member (NodeRaftState , [leader , follower ])
4956
+ end , Status2 )),
4957
+ % Remove "Node Name" and "Raft State" from the status.
4958
+ Status3 = [NE1 , NE2 , NE3 ]= [
4959
+ begin
4960
+ R = proplists :delete (<<" Node Name" >>, NodeEntry ),
4961
+ proplists :delete (<<" Raft State" >>, R )
4962
+ end || NodeEntry <- Status2 ],
4963
+ % Check all other properties have same value on all nodes.
4964
+ ct :pal (" Status3: ~tp " , [Status3 ]),
4965
+ [
4966
+ begin
4967
+ ? assertEqual (V , proplists :get_value (K , NE2 )),
4968
+ ? assertEqual (V , proplists :get_value (K , NE3 ))
4969
+ end || {K , V } <- NE1
4970
+ ].
4971
+
4972
+ % Testcase motivated by : https://github.com/rabbitmq/rabbitmq-server/issues/12366
4973
+ no_messages_after_queue_reincarnation (Config ) ->
4974
+ [S1 , S2 , S3 ] = rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
4975
+ Ch = rabbit_ct_client_helpers :open_channel (Config , S1 ),
4976
+ QName = <<" QQ" >>,
4977
+
4978
+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
4979
+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
4980
+
4981
+ [Q ] = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , list , []),
4982
+
4983
+ publish (Ch , QName , <<" msg1" >>),
4984
+ publish (Ch , QName , <<" msg2" >>),
4985
+
4986
+ % % Stop S3
4987
+ rabbit_ct_broker_helpers :mark_as_being_drained (Config , S3 ),
4988
+ ? assertEqual (ok , rabbit_control_helper :command (stop_app , S3 )),
4989
+
4990
+ qos (Ch , 1 , false ),
4991
+ subscribe (Ch , QName , false , <<" tag0" >>, [], 500 ),
4992
+ DeliveryTag = receive
4993
+ {# 'basic.deliver' {delivery_tag = DT }, # amqp_msg {}} ->
4994
+ receive
4995
+ {# 'basic.deliver' {consumer_tag = <<" tag0" >>}, # amqp_msg {}} ->
4996
+ ct :fail (" did not expect the second one" )
4997
+ after 500 ->
4998
+ DT
4999
+ end
5000
+ after 500 ->
5001
+ ct :fail (" Expected some delivery, but got none" )
5002
+ end ,
5003
+
5004
+ % % Delete and re-declare queue with the same name.
5005
+ rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_amqqueue , delete , [Q ,false ,false ,<<" dummy_user" >>]),
5006
+ ? assertEqual ({'queue.declare_ok' , QName , 0 , 0 },
5007
+ declare (Ch , QName , [{<<" x-queue-type" >>, longstr , <<" quorum" >>}])),
5008
+
5009
+ % % Bumping term in online nodes
5010
+ rabbit_ct_broker_helpers :rpc (Config , 1 , rabbit_quorum_queue , transfer_leadership , [Q , S2 ]),
5011
+
5012
+ % % Restart S3
5013
+ ? assertEqual (ok , rabbit_control_helper :command (start_app , S3 )),
5014
+
5015
+ ok = amqp_channel :cast (Ch , # 'basic.ack' {delivery_tag = DeliveryTag ,
5016
+ multiple = false }),
5017
+ % % No message should be delivered after reincarnation
5018
+ receive
5019
+ {# 'basic.deliver' {consumer_tag = <<" tag0" >>}, # amqp_msg {}} ->
5020
+ ct :fail (" Expected no deliveries, but got one" )
5021
+ after 500 ->
5022
+ ok
5023
+ end .
5024
+
4883
5025
% %----------------------------------------------------------------------------
4884
5026
4885
5027
same_elements (L1 , L2 )
@@ -4949,7 +5091,10 @@ consume_empty(Ch, Queue, NoAck) ->
4949
5091
subscribe (Ch , Queue , NoAck ) ->
4950
5092
subscribe (Ch , Queue , NoAck , <<" ctag" >>, []).
4951
5093
5094
+
4952
5095
subscribe (Ch , Queue , NoAck , Tag , Args ) ->
5096
+ subscribe (Ch , Queue , NoAck , Tag , Args , ? TIMEOUT ).
5097
+ subscribe (Ch , Queue , NoAck , Tag , Args , Timeout ) ->
4953
5098
amqp_channel :subscribe (Ch , # 'basic.consume' {queue = Queue ,
4954
5099
no_ack = NoAck ,
4955
5100
arguments = Args ,
@@ -4958,7 +5103,7 @@ subscribe(Ch, Queue, NoAck, Tag, Args) ->
4958
5103
receive
4959
5104
# 'basic.consume_ok' {consumer_tag = Tag } ->
4960
5105
ok
4961
- after ? TIMEOUT ->
5106
+ after Timeout ->
4962
5107
flush (100 ),
4963
5108
exit (subscribe_timeout )
4964
5109
end .
0 commit comments