1212-include_lib (" amqp_client/include/amqp_client.hrl" ).
1313-compile ([nowarn_export_all , export_all ]).
1414
15+ % % The reconciler has two modes of triggering itself
16+ % % - timer based
17+ % % - event based
18+ % % The default config of this test has Interval very short - 5 second which is lower than
19+ % % wait_until timeout. Meaninig that even if all domain triggers (node_up/down, policy_set, etc)
20+ % % are disconnected tests would be still green.
21+ % % So to test triggers it is essential to set Interval high enough (the very default value of 60 minutes is perfect)
22+ % %
23+ % % TODO: test `policy_set` trigger
1524
1625all () ->
1726 [
18- {group , unclustered }
27+ {group , unclustered },
28+ {group , unclustered_triggers }
1929 ].
2030
2131groups () ->
2232 [
23- {unclustered , [],
33+ {unclustered , [], % % low interval, even if triggers do not work all tests should pass
2434 [
2535 {quorum_queue_3 , [], [auto_grow , auto_grow_drained_node , auto_shrink ]}
36+ ]},
37+ % % uses an interval longer than `wait_until` (30s by default)
38+ {unclustered_triggers , [],
39+ [
40+ % % see also `auto_grow_drained_node`
41+ {quorum_queue_3 , [], [auto_grow , auto_shrink ]}
2642 ]}
2743 ].
2844
2945% % -------------------------------------------------------------------
3046% % Testsuite setup/teardown.
3147% % -------------------------------------------------------------------
3248
33- init_per_suite (Config0 ) ->
49+ init_per_suite (Config ) ->
3450 rabbit_ct_helpers :log_environment (),
51+ rabbit_ct_helpers :run_setup_steps (Config , []).
52+
53+ end_per_suite (Config ) ->
54+ rabbit_ct_helpers :run_teardown_steps (Config ).
55+
56+ init_per_group (unclustered , Config0 ) ->
3557 Config1 = rabbit_ct_helpers :merge_app_env (
3658 Config0 , {rabbit , [{quorum_tick_interval , 1000 },
3759 {quorum_membership_reconciliation_enabled , true },
3860 {quorum_membership_reconciliation_auto_remove , true },
3961 {quorum_membership_reconciliation_interval , 5000 },
4062 {quorum_membership_reconciliation_trigger_interval , 2000 },
4163 {quorum_membership_reconciliation_target_group_size , 3 }]}),
42- rabbit_ct_helpers :run_setup_steps (Config1 , []).
43-
44- end_per_suite (Config ) ->
45- rabbit_ct_helpers :run_teardown_steps (Config ).
46- init_per_group (unclustered , Config ) ->
47- rabbit_ct_helpers :set_config (Config , [{rmq_nodes_clustered , false }]);
64+ rabbit_ct_helpers :set_config (Config1 , [{rmq_nodes_clustered , false }]);
65+ init_per_group (unclustered_triggers , Config0 ) ->
66+ Config1 = rabbit_ct_helpers :merge_app_env (
67+ Config0 , {rabbit , [{quorum_tick_interval , 1000 },
68+ {quorum_membership_reconciliation_enabled , true },
69+ {quorum_membership_reconciliation_auto_remove , true },
70+ {quorum_membership_reconciliation_interval , 50000 },
71+ {quorum_membership_reconciliation_trigger_interval , 2000 },
72+ {quorum_membership_reconciliation_target_group_size , 3 }]}),
73+ % % shrink timeout is set here because without it, when a node stopped right after a queue was created,
74+ % % the test will pass without any triggers because cluster change will likely happen before the trigger_interval,
75+ % % scheduled in response to queue_created event.
76+ % % See also a comment in `auto_shrink/1`.
77+ rabbit_ct_helpers :set_config (Config1 , [{rmq_nodes_clustered , false },
78+ {quorum_membership_reconciliation_interval , 50000 },
79+ {shrink_timeout , 2000 }]);
4880init_per_group (Group , Config ) ->
4981 ClusterSize = 3 ,
5082 Config1 = rabbit_ct_helpers :set_config (Config ,
@@ -57,6 +89,8 @@ init_per_group(Group, Config) ->
5789
5890end_per_group (unclustered , Config ) ->
5991 Config ;
92+ end_per_group (unclustered_triggers , Config ) ->
93+ Config ;
6094end_per_group (_ , Config ) ->
6195 rabbit_ct_helpers :run_steps (Config ,
6296 rabbit_ct_broker_helpers :teardown_steps ()).
@@ -72,34 +106,17 @@ init_per_testcase(Testcase, Config) ->
72106 ]),
73107 rabbit_ct_helpers :run_steps (Config2 , rabbit_ct_client_helpers :setup_steps ()).
74108
75- merge_app_env (Config ) ->
76- rabbit_ct_helpers :merge_app_env (
77- rabbit_ct_helpers :merge_app_env (Config ,
78- {rabbit , [{core_metrics_gc_interval , 100 }]}),
79- {ra , [{min_wal_roll_over_interval , 30000 }]}).
80-
81109end_per_testcase (Testcase , Config ) ->
82110 [Server0 , Server1 , Server2 ] =
83111 rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
112+ Ch = rabbit_ct_client_helpers :open_channel (Config , Server1 ),
113+ amqp_channel :call (Ch , # 'queue.delete' {queue = rabbit_data_coercion :to_binary (Testcase )}),
84114 reset_nodes ([Server2 , Server0 ], Server1 ),
85115 Config1 = rabbit_ct_helpers :run_steps (
86116 Config ,
87117 rabbit_ct_client_helpers :teardown_steps ()),
88118 rabbit_ct_helpers :testcase_finished (Config1 , Testcase ).
89119
90- reset_nodes ([], _Leader ) ->
91- ok ;
92- reset_nodes ([Node | Nodes ], Leader ) ->
93- ok = rabbit_control_helper :command (stop_app , Node ),
94- case rabbit_control_helper :command (forget_cluster_node , Leader , [atom_to_list (Node )]) of
95- ok -> ok ;
96- {error , _ , <<" Error:\n {:not_a_cluster_node, ~c \" The node selected is not in the cluster.\" }" >>} -> ok
97- end ,
98- ok = rabbit_control_helper :command (reset , Node ),
99- ok = rabbit_control_helper :command (start_app , Node ),
100- reset_nodes (Nodes , Leader ).
101-
102-
103120% % -------------------------------------------------------------------
104121% % Testcases.
105122% % -------------------------------------------------------------------
@@ -134,6 +151,10 @@ auto_grow(Config) ->
134151 end ).
135152
136153auto_grow_drained_node (Config ) ->
154+ % % NOTE: with large Interval (larger than wait_until) test will fail.
155+ % % the reason is that entering/exiting drain state does not emit events
156+ % % and even if they did via gen_event, they going to be only local to that node.
157+ % % so reconciliator has no choice but to wait full Interval
137158 [Server0 , Server1 , Server2 ] =
138159 rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
139160 Ch = rabbit_ct_client_helpers :open_channel (Config , Server1 ),
@@ -169,7 +190,6 @@ auto_grow_drained_node(Config) ->
169190 3 =:= length (M )
170191 end ).
171192
172-
173193auto_shrink (Config ) ->
174194 [Server0 , Server1 , Server2 ] =
175195 rabbit_ct_broker_helpers :get_node_configs (Config , nodename ),
@@ -186,6 +206,18 @@ auto_shrink(Config) ->
186206 Server1 }),
187207 3 =:= length (M )
188208 end ),
209+
210+ % % QQ member reconciliation does not act immediately but rather after a scheduled delay.
211+ % % So if this test wants to test that the reconciliator reacts to, say, node_down or a similar event,
212+ % % it has to wait at least a trigger_interval ms to pass before removing node. Otherwise
213+ % % the shrink effect would come from the previous trigger.
214+ % %
215+ % % When a `queue_created` trigger set up a timer to fire after a trigger_interval, the queue has 3 members
216+ % % and stop_app executes much quicker than the trigger_interval. Therefore the number of members
217+ % % will be updated even without a node_down event.
218+
219+ timer :sleep (rabbit_ct_helpers :get_config (Config , shrink_timeout , 0 )),
220+
189221 ok = rabbit_control_helper :command (stop_app , Server2 ),
190222 ok = rabbit_ct_broker_helpers :rpc (Config , 0 , rabbit_db_cluster , forget_member ,
191223 [Server2 , false ]),
@@ -196,7 +228,27 @@ auto_shrink(Config) ->
196228 2 =:= length (M )
197229 end ).
198230
231+ % % -------------------------------------------------------------------
232+ % % Helpers.
233+ % % -------------------------------------------------------------------
199234
235+ merge_app_env (Config ) ->
236+ rabbit_ct_helpers :merge_app_env (
237+ rabbit_ct_helpers :merge_app_env (Config ,
238+ {rabbit , [{core_metrics_gc_interval , 100 }]}),
239+ {ra , [{min_wal_roll_over_interval , 30000 }]}).
240+
241+ reset_nodes ([], _Leader ) ->
242+ ok ;
243+ reset_nodes ([Node | Nodes ], Leader ) ->
244+ ok = rabbit_control_helper :command (stop_app , Node ),
245+ case rabbit_control_helper :command (forget_cluster_node , Leader , [atom_to_list (Node )]) of
246+ ok -> ok ;
247+ {error , _ , <<" Error:\n {:not_a_cluster_node, ~c \" The node selected is not in the cluster.\" }" >>} -> ok
248+ end ,
249+ ok = rabbit_control_helper :command (reset , Node ),
250+ ok = rabbit_control_helper :command (start_app , Node ),
251+ reset_nodes (Nodes , Leader ).
200252
201253add_server_to_cluster (Server , Leader ) ->
202254 ok = rabbit_control_helper :command (stop_app , Server ),
0 commit comments