@@ -46,68 +46,70 @@ groups() ->
46
46
{unclustered , [], [
47
47
{uncluster_size_2 , [], [add_member ]}
48
48
]},
49
- {clustered , [], [
50
- {cluster_size_2 , [], [add_member_2 ,
51
- add_member_not_running ,
52
- add_member_classic ,
53
- add_member_wrong_type ,
54
- add_member_already_a_member ,
55
- add_member_not_found ,
56
- delete_member_not_running ,
57
- delete_member_classic ,
58
- delete_member_wrong_type ,
59
- delete_member_queue_not_found ,
60
- delete_member ,
61
- delete_member_not_a_member ,
62
- delete_member_member_already_deleted ,
63
- node_removal_is_quorum_critical ]
64
- ++ memory_tests ()},
65
- {cluster_size_3 , [], [
66
- cleanup_data_dir ,
67
- channel_handles_ra_event ,
68
- declare_during_node_down ,
69
- simple_confirm_availability_on_leader_change ,
70
- publishing_to_unavailable_queue ,
71
- confirm_availability_on_leader_change ,
72
- recover_from_single_failure ,
73
- recover_from_multiple_failures ,
74
- leadership_takeover ,
75
- delete_declare ,
76
- delete_member_during_node_down ,
77
- metrics_cleanup_on_leadership_takeover ,
78
- metrics_cleanup_on_leader_crash ,
79
- consume_in_minority ,
80
- reject_after_leader_transfer ,
81
- shrink_all ,
82
- rebalance ,
83
- file_handle_reservations ,
84
- file_handle_reservations_above_limit ,
85
- node_removal_is_not_quorum_critical ,
86
- leader_locator_client_local ,
87
- leader_locator_balanced ,
88
- leader_locator_balanced_maintenance ,
89
- leader_locator_balanced_random_maintenance ,
90
- leader_locator_policy ,
91
- status ,
92
- format ,
93
- add_member_2
94
- ]
95
- ++ all_tests ()},
96
- {cluster_size_5 , [], [start_queue ,
97
- start_queue_concurrent ,
98
- quorum_cluster_size_3 ,
99
- quorum_cluster_size_7 ,
100
- node_removal_is_not_quorum_critical ,
101
- select_nodes_with_least_replicas ,
102
- select_nodes_with_least_replicas_node_down
103
- ]},
104
- {clustered_with_partitions , [],
105
- [
106
- reconnect_consumer_and_publish ,
107
- reconnect_consumer_and_wait ,
108
- reconnect_consumer_and_wait_channel_down
109
- ]}
110
- ]}
49
+ {clustered , [],
50
+ [
51
+ {cluster_size_2 , [], [add_member_2 ,
52
+ add_member_not_running ,
53
+ add_member_classic ,
54
+ add_member_wrong_type ,
55
+ add_member_already_a_member ,
56
+ add_member_not_found ,
57
+ delete_member_not_running ,
58
+ delete_member_classic ,
59
+ delete_member_wrong_type ,
60
+ delete_member_queue_not_found ,
61
+ delete_member ,
62
+ delete_member_not_a_member ,
63
+ node_removal_is_quorum_critical ]
64
+ ++ memory_tests ()},
65
+ {cluster_size_3 , [], [
66
+ cleanup_data_dir ,
67
+ channel_handles_ra_event ,
68
+ declare_during_node_down ,
69
+ simple_confirm_availability_on_leader_change ,
70
+ publishing_to_unavailable_queue ,
71
+ confirm_availability_on_leader_change ,
72
+ recover_from_single_failure ,
73
+ recover_from_multiple_failures ,
74
+ leadership_takeover ,
75
+ delete_declare ,
76
+ delete_member_during_node_down ,
77
+ metrics_cleanup_on_leadership_takeover ,
78
+ metrics_cleanup_on_leader_crash ,
79
+ consume_in_minority ,
80
+ reject_after_leader_transfer ,
81
+ shrink_all ,
82
+ rebalance ,
83
+ file_handle_reservations ,
84
+ file_handle_reservations_above_limit ,
85
+ node_removal_is_not_quorum_critical ,
86
+ leader_locator_client_local ,
87
+ leader_locator_balanced ,
88
+ leader_locator_balanced_maintenance ,
89
+ leader_locator_balanced_random_maintenance ,
90
+ leader_locator_policy ,
91
+ status ,
92
+ format ,
93
+ add_member_2 ,
94
+ single_active_consumer_priority_take_over ,
95
+ single_active_consumer_priority
96
+ ]
97
+ ++ all_tests ()},
98
+ {cluster_size_5 , [], [start_queue ,
99
+ start_queue_concurrent ,
100
+ quorum_cluster_size_3 ,
101
+ quorum_cluster_size_7 ,
102
+ node_removal_is_not_quorum_critical ,
103
+ select_nodes_with_least_replicas ,
104
+ select_nodes_with_least_replicas_node_down
105
+ ]},
106
+ {clustered_with_partitions , [],
107
+ [
108
+ reconnect_consumer_and_publish ,
109
+ reconnect_consumer_and_wait ,
110
+ reconnect_consumer_and_wait_channel_down
111
+ ]}
112
+ ]}
111
113
].
112
114
113
115
all_tests () ->
@@ -923,6 +925,7 @@ publish_confirm(Ch, QName, Timeout) ->
923
925
ct :pal (" NOT CONFIRMED! ~ts " , [QName ]),
924
926
fail
925
927
after Timeout ->
928
+ flush (1 ),
926
929
exit (confirm_timeout )
927
930
end .
928
931
@@ -971,6 +974,120 @@ consume_in_minority(Config) ->
971
974
ok = rabbit_ct_broker_helpers :wait_for_async_start_node (Server2 ),
972
975
ok .
973
976
977
+ single_active_consumer_priority_take_over (Config ) ->
978
+ check_quorum_queues_v4_compat (Config ),
979
+
980
+ [Server0 , Server1 , _Server2 ] =
981
+ rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
982
+ Ch1 = rabbit_ct_client_helpers :open_channel (Config , Server0 ),
983
+ Ch2 = rabbit_ct_client_helpers :open_channel (Config , Server1 ),
984
+ QName = ? config (queue_name , Config ),
985
+ Q1 = <<QName /binary , " _1" >>,
986
+ RaNameQ1 = binary_to_atom (<<" %2F" , " _" , Q1 /binary >>, utf8 ),
987
+ QueryFun = fun rabbit_fifo :query_single_active_consumer /1 ,
988
+ Args = [{<<" x-queue-type" >>, longstr , <<" quorum" >>},
989
+ {<<" x-single-active-consumer" >>, bool , true }],
990
+ ? assertEqual ({'queue.declare_ok' , Q1 , 0 , 0 }, declare (Ch1 , Q1 , Args )),
991
+ ok = subscribe (Ch1 , Q1 , false , <<" ch1-ctag1" >>, [{" x-priority" , byte , 1 }]),
992
+ ? assertMatch ({ok , {_ , {value , {<<" ch1-ctag1" >>, _ }}}, _ },
993
+ rpc :call (Server0 , ra , local_query , [RaNameQ1 , QueryFun ])),
994
+ # 'confirm.select_ok' {} = amqp_channel :call (Ch2 , # 'confirm.select' {}),
995
+ publish_confirm (Ch2 , Q1 ),
996
+ % % higher priority consumer attaches
997
+ ok = subscribe (Ch2 , Q1 , false , <<" ch2-ctag1" >>, [{" x-priority" , byte , 3 }]),
998
+
999
+ % % Q1 should still have Ch1 as consumer as it has pending messages
1000
+ ? assertMatch ({ok , {_ , {value , {<<" ch1-ctag1" >>, _ }}}, _ },
1001
+ rpc :call (Server0 , ra , local_query ,
1002
+ [RaNameQ1 , QueryFun ])),
1003
+
1004
+ % % ack the message
1005
+ receive
1006
+ {# 'basic.deliver' {consumer_tag = <<" ch1-ctag1" >>,
1007
+ delivery_tag = DeliveryTag }, _ } ->
1008
+ amqp_channel :cast (Ch1 , # 'basic.ack' {delivery_tag = DeliveryTag ,
1009
+ multiple = false })
1010
+ after 5000 ->
1011
+ flush (1 ),
1012
+ exit (basic_deliver_timeout )
1013
+ end ,
1014
+
1015
+ ? awaitMatch ({ok , {_ , {value , {<<" ch2-ctag1" >>, _ }}}, _ },
1016
+ rpc :call (Server0 , ra , local_query , [RaNameQ1 , QueryFun ]),
1017
+ ? DEFAULT_AWAIT ),
1018
+ ok .
1019
+
1020
+ single_active_consumer_priority (Config ) ->
1021
+ check_quorum_queues_v4_compat (Config ),
1022
+ [Server0 , Server1 , Server2 ] =
1023
+ rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
1024
+
1025
+ Ch1 = rabbit_ct_client_helpers :open_channel (Config , Server0 ),
1026
+ Ch2 = rabbit_ct_client_helpers :open_channel (Config , Server1 ),
1027
+ Ch3 = rabbit_ct_client_helpers :open_channel (Config , Server2 ),
1028
+ QName = ? config (queue_name , Config ),
1029
+ Q1 = <<QName /binary , " _1" >>,
1030
+ Q2 = <<QName /binary , " _2" >>,
1031
+ Q3 = <<QName /binary , " _3" >>,
1032
+ Args = [{<<" x-queue-type" >>, longstr , <<" quorum" >>},
1033
+ {<<" x-single-active-consumer" >>, bool , true }],
1034
+ ? assertEqual ({'queue.declare_ok' , Q1 , 0 , 0 }, declare (Ch1 , Q1 , Args )),
1035
+ ? assertEqual ({'queue.declare_ok' , Q2 , 0 , 0 }, declare (Ch2 , Q2 , Args )),
1036
+ ? assertEqual ({'queue.declare_ok' , Q3 , 0 , 0 }, declare (Ch3 , Q3 , Args )),
1037
+
1038
+ ok = subscribe (Ch1 , Q1 , false , <<" ch1-ctag1" >>, [{" x-priority" , byte , 3 }]),
1039
+ ok = subscribe (Ch1 , Q2 , false , <<" ch1-ctag2" >>, [{" x-priority" , byte , 2 }]),
1040
+ ok = subscribe (Ch1 , Q3 , false , <<" ch1-ctag3" >>, [{" x-priority" , byte , 1 }]),
1041
+
1042
+
1043
+ ok = subscribe (Ch2 , Q1 , false , <<" ch2-ctag1" >>, [{" x-priority" , byte , 1 }]),
1044
+ ok = subscribe (Ch2 , Q2 , false , <<" ch2-ctag2" >>, [{" x-priority" , byte , 3 }]),
1045
+ ok = subscribe (Ch2 , Q3 , false , <<" ch2-ctag3" >>, [{" x-priority" , byte , 2 }]),
1046
+
1047
+ ok = subscribe (Ch3 , Q1 , false , <<" ch3-ctag1" >>, [{" x-priority" , byte , 2 }]),
1048
+ ok = subscribe (Ch3 , Q2 , false , <<" ch3-ctag2" >>, [{" x-priority" , byte , 1 }]),
1049
+ ok = subscribe (Ch3 , Q3 , false , <<" ch3-ctag3" >>, [{" x-priority" , byte , 3 }]),
1050
+
1051
+
1052
+ RaNameQ1 = binary_to_atom (<<" %2F" , " _" , Q1 /binary >>, utf8 ),
1053
+ RaNameQ2 = binary_to_atom (<<" %2F" , " _" , Q2 /binary >>, utf8 ),
1054
+ RaNameQ3 = binary_to_atom (<<" %2F" , " _" , Q3 /binary >>, utf8 ),
1055
+ % % assert each queue has a different consumer
1056
+ QueryFun = fun rabbit_fifo :query_single_active_consumer /1 ,
1057
+
1058
+ % % Q1 should have the consumer on Ch1
1059
+ ? assertMatch ({ok , {_ , {value , {<<" ch1-ctag1" >>, _ }}}, _ },
1060
+ rpc :call (Server0 , ra , local_query , [RaNameQ1 , QueryFun ])),
1061
+
1062
+ % % Q2 Ch2
1063
+ ? assertMatch ({ok , {_ , {value , {<<" ch2-ctag2" >>, _ }}}, _ },
1064
+ rpc :call (Server1 , ra , local_query , [RaNameQ2 , QueryFun ])),
1065
+
1066
+ % % Q3 Ch3
1067
+ ? assertMatch ({ok , {_ , {value , {<<" ch3-ctag3" >>, _ }}}, _ },
1068
+ rpc :call (Server2 , ra , local_query , [RaNameQ3 , QueryFun ])),
1069
+
1070
+ % % close Ch3
1071
+ _ = rabbit_ct_client_helpers :close_channel (Ch3 ),
1072
+ flush (100 ),
1073
+
1074
+ % % assert Q3 has Ch2 (priority 2) as consumer
1075
+ ? assertMatch ({ok , {_ , {value , {<<" ch2-ctag3" >>, _ }}}, _ },
1076
+ rpc :call (Server2 , ra , local_query , [RaNameQ3 , QueryFun ])),
1077
+
1078
+ % % close Ch2
1079
+ _ = rabbit_ct_client_helpers :close_channel (Ch2 ),
1080
+ flush (100 ),
1081
+
1082
+ % % assert all queues as has Ch1 as consumer
1083
+ ? assertMatch ({ok , {_ , {value , {<<" ch1-ctag1" >>, _ }}}, _ },
1084
+ rpc :call (Server0 , ra , local_query , [RaNameQ1 , QueryFun ])),
1085
+ ? assertMatch ({ok , {_ , {value , {<<" ch1-ctag2" >>, _ }}}, _ },
1086
+ rpc :call (Server0 , ra , local_query , [RaNameQ2 , QueryFun ])),
1087
+ ? assertMatch ({ok , {_ , {value , {<<" ch1-ctag3" >>, _ }}}, _ },
1088
+ rpc :call (Server0 , ra , local_query , [RaNameQ3 , QueryFun ])),
1089
+ ok .
1090
+
974
1091
reject_after_leader_transfer (Config ) ->
975
1092
[Server0 , Server1 , Server2 ] =
976
1093
rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
@@ -3649,13 +3766,20 @@ consume_empty(Ch, Queue, NoAck) ->
3649
3766
no_ack = NoAck })).
3650
3767
3651
3768
subscribe (Ch , Queue , NoAck ) ->
3769
+ subscribe (Ch , Queue , NoAck , <<" ctag" >>, []).
3770
+
3771
+ subscribe (Ch , Queue , NoAck , Tag , Args ) ->
3652
3772
amqp_channel :subscribe (Ch , # 'basic.consume' {queue = Queue ,
3653
3773
no_ack = NoAck ,
3654
- consumer_tag = <<" ctag" >>},
3774
+ arguments = Args ,
3775
+ consumer_tag = Tag },
3655
3776
self ()),
3656
3777
receive
3657
- # 'basic.consume_ok' {consumer_tag = << " ctag " >> } ->
3778
+ # 'basic.consume_ok' {consumer_tag = Tag } ->
3658
3779
ok
3780
+ after 30000 ->
3781
+ flush (100 ),
3782
+ exit (subscribe_timeout )
3659
3783
end .
3660
3784
3661
3785
qos (Ch , Prefetch , Global ) ->
@@ -3768,3 +3892,12 @@ basic_get(Ch, Q, NoAck, Attempt) ->
3768
3892
timer :sleep (100 ),
3769
3893
basic_get (Ch , Q , NoAck , Attempt - 1 )
3770
3894
end .
3895
+
3896
+ check_quorum_queues_v4_compat (Config ) ->
3897
+ case rabbit_ct_broker_helpers :is_feature_flag_enabled (Config ,
3898
+ quorum_queues_4 ) of
3899
+ false ->
3900
+ throw ({skip , " test needs feature flag quorum_queues_v4" });
3901
+ true ->
3902
+ ok
3903
+ end .
0 commit comments