Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
%% This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
%% License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
%%
|
2024-02-06 00:53:36 +08:00
|
|
|
%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
%%
|
|
|
|
|
|
|
|
-module(deprecated_features_SUITE).
|
|
|
|
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
-include_lib("common_test/include/ct.hrl").
|
|
|
|
|
|
|
|
-export([suite/0,
|
|
|
|
all/0,
|
|
|
|
groups/0,
|
|
|
|
init_per_suite/1,
|
|
|
|
end_per_suite/1,
|
|
|
|
init_per_group/2,
|
|
|
|
end_per_group/2,
|
|
|
|
init_per_testcase/2,
|
|
|
|
end_per_testcase/2,
|
|
|
|
|
|
|
|
use_unknown_deprecated_feature/1,
|
|
|
|
use_deprecated_feature_permitted_by_default_everywhere/1,
|
|
|
|
use_deprecated_feature_denied_by_default_everywhere/1,
|
|
|
|
use_deprecated_feature_disconnected_everywhere/1,
|
|
|
|
use_deprecated_feature_removed_everywhere/1,
|
|
|
|
override_permitted_by_default_in_configuration/1,
|
|
|
|
override_denied_by_default_in_configuration/1,
|
|
|
|
override_disconnected_in_configuration/1,
|
|
|
|
override_removed_in_configuration/1,
|
|
|
|
has_is_feature_used_cb_returning_false/1,
|
|
|
|
has_is_feature_used_cb_returning_true/1,
|
|
|
|
get_appropriate_warning_when_permitted/1,
|
|
|
|
get_appropriate_warning_when_denied/1,
|
|
|
|
get_appropriate_warning_when_disconnected/1,
|
|
|
|
get_appropriate_warning_when_removed/1,
|
2023-07-17 23:59:55 +08:00
|
|
|
deprecated_feature_enabled_if_feature_flag_depends_on_it/1,
|
2023-11-10 17:50:34 +08:00
|
|
|
list_all_deprecated_features/1,
|
|
|
|
list_used_deprecated_features/1,
|
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
|
|
|
|
feature_is_unused/1,
|
|
|
|
feature_is_used/1
|
|
|
|
]).
|
|
|
|
|
|
|
|
suite() ->
|
|
|
|
[{timetrap, {minutes, 1}}].
|
|
|
|
|
|
|
|
all() ->
|
|
|
|
[
|
|
|
|
{group, cluster_size_1},
|
|
|
|
{group, cluster_size_3}
|
|
|
|
].
|
|
|
|
|
|
|
|
groups() ->
|
|
|
|
Tests = [
|
|
|
|
use_unknown_deprecated_feature,
|
|
|
|
use_deprecated_feature_permitted_by_default_everywhere,
|
|
|
|
use_deprecated_feature_denied_by_default_everywhere,
|
|
|
|
use_deprecated_feature_disconnected_everywhere,
|
|
|
|
use_deprecated_feature_removed_everywhere,
|
|
|
|
override_permitted_by_default_in_configuration,
|
|
|
|
override_denied_by_default_in_configuration,
|
|
|
|
override_disconnected_in_configuration,
|
|
|
|
override_removed_in_configuration,
|
|
|
|
has_is_feature_used_cb_returning_false,
|
|
|
|
has_is_feature_used_cb_returning_true,
|
|
|
|
get_appropriate_warning_when_permitted,
|
|
|
|
get_appropriate_warning_when_denied,
|
|
|
|
get_appropriate_warning_when_disconnected,
|
2023-07-17 23:59:55 +08:00
|
|
|
get_appropriate_warning_when_removed,
|
2023-11-10 17:50:34 +08:00
|
|
|
deprecated_feature_enabled_if_feature_flag_depends_on_it,
|
|
|
|
list_all_deprecated_features,
|
|
|
|
list_used_deprecated_features
|
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
],
|
|
|
|
[
|
|
|
|
{cluster_size_1, [], Tests},
|
|
|
|
{cluster_size_3, [], Tests}
|
|
|
|
].
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%% Testsuite setup/teardown.
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
|
|
|
init_per_suite(Config) ->
|
|
|
|
rabbit_ct_helpers:log_environment(),
|
|
|
|
logger:set_primary_config(level, debug),
|
2024-08-23 23:01:47 +08:00
|
|
|
rabbit_ct_helpers:run_setup_steps(Config, []).
|
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
|
|
|
|
end_per_suite(Config) ->
|
|
|
|
Config.
|
|
|
|
|
|
|
|
init_per_group(cluster_size_1, Config) ->
|
|
|
|
rabbit_ct_helpers:set_config(Config, {nodes_count, 1});
|
|
|
|
init_per_group(cluster_size_3, Config) ->
|
|
|
|
rabbit_ct_helpers:set_config(Config, {nodes_count, 3});
|
|
|
|
init_per_group(_Group, Config) ->
|
|
|
|
Config.
|
|
|
|
|
|
|
|
end_per_group(_Group, Config) ->
|
|
|
|
Config.
|
|
|
|
|
|
|
|
init_per_testcase(Testcase, Config) ->
|
2023-07-17 23:59:55 +08:00
|
|
|
NodesCount = ?config(nodes_count, Config),
|
|
|
|
NodenamePrefix = list_to_atom(
|
|
|
|
lists:flatten(
|
|
|
|
io_lib:format("~s-cs~b", [Testcase, NodesCount]))),
|
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
rabbit_ct_helpers:run_steps(
|
|
|
|
Config,
|
|
|
|
[fun(Cfg) ->
|
2023-07-17 23:59:55 +08:00
|
|
|
feature_flags_v2_SUITE:start_slave_nodes(Cfg, NodenamePrefix)
|
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not
only in our communication. The new module allows to disallow the use of
a deprecated feature and/or warn the user when he relies on such a
feature.
[Why]
Currently, we only tell people about deprecated features through blog
posts and the mailing-list. This might be insufficiant for our users
that a feature they use will be removed in a future version:
* They may not read our blog or mailing-list
* They may not understand that they use such a deprecated feature
* They might wait for the big removal before they plan testing
* They might not take it seriously enough
The idea behind this patch is to increase the chance that users notice
that they are using something which is about to be dropped from
RabbitMQ. Anopther benefit is that they should be able to test how
RabbitMQ will behave in the future before the actual removal. This
should allow them to test and plan changes.
[How]
When a feature is deprecated in other large projects (such as FreeBSD
where I took the idea from), it goes through a lifecycle:
1. The feature is still available, but users get a warning somehow when
they use it. They can disable it to test.
2. The feature is still available, but disabled out-of-the-box. Users
can re-enable it (and get a warning).
3. The feature is disconnected from the build. Therefore, the code
behind it is still there, but users have to recompile the thing to be
able to use it.
4. The feature is removed from the source code. Users have to adapt or
they can't upgrade anymore.
The solution in this patch offers the same lifecycle. A deprecated
feature will be in one of these deprecation phases:
1. `permitted_by_default`: The feature is available. Users get a warning
if they use it. They can disable it from the configuration.
2. `denied_by_default`: The feature is available but disabled by
default. Users get an error if they use it and RabbitMQ behaves like
the feature is removed. They can re-enable is from the configuration
and get a warning.
3. `disconnected`: The feature is present in the source code, but is
disabled and can't be re-enabled without recompiling RabbitMQ. Users
get the same behavior as if the code was removed.
4. `removed`: The feature's code is gone.
The whole thing is based on the feature flags subsystem, but it has the
following differences with other feature flags:
* The semantic is reversed: the feature flag behind a deprecated feature
is disabled when the deprecated feature is permitted, or enabled when
the deprecated feature is denied.
* The feature flag behind a deprecated feature is enabled out-of-the-box
(meaning the deprecated feature is denied):
* if the deprecation phase is `permitted_by_default` and the
configuration denies the deprecated feature
* if the deprecation phase is `denied_by_default` and the
configuration doesn't permit the deprecated feature
* if the deprecation phase is `disconnected` or `removed`
* Feature flags behind deprecated feature don't appear in feature flags
listings.
Otherwise, deprecated features' feature flags are managed like other
feature flags, in particular inside clusters.
To declare a deprecated feature:
-rabbit_deprecated_feature(
{my_deprecated_feature,
#{deprecation_phase => permitted_by_default,
msgs => #{when_permitted => "This feature will be removed in RabbitMQ X.0"},
}}).
Then, to check the state of a deprecated feature in the code:
case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of
true ->
%% The deprecated feature is still permitted.
ok;
false ->
%% The deprecated feature is gone or should be considered
%% unavailable.
error
end.
Warnings and errors are logged automatically. A message is generated
automatically, but it is possible to define a message in the deprecated
feature flag declaration like in the example above.
Here is an example of a logged warning that was generated automatically:
Feature `my_deprecated_feature` is deprecated.
By default, this feature can still be used for now.
Its use will not be permitted by default in a future minor RabbitMQ version and the feature will be removed from a future major RabbitMQ version; actual versions to be determined.
To continue using this feature when it is not permitted by default, set the following parameter in your configuration:
"deprecated_features.permit.my_deprecated_feature = true"
To test RabbitMQ as if the feature was removed, set this in your configuration:
"deprecated_features.permit.my_deprecated_feature = false"
To override the default state of `permitted_by_default` and
`denied_by_default` deprecation phases, users can set the following
configuration:
# In rabbitmq.conf:
deprecated_features.permit.my_deprecated_feature = true # or false
The actual behavior protected by a deprecated feature check is out of
scope for this subsystem. It is the repsonsibility of each deprecated
feature code to determine what to do when the deprecated feature is
denied.
V1: Deprecated feature states are initially computed during the
initialization of the registry, based on their deprecation phase and
possibly the configuration. They don't go through the `enable/1`
code at all.
V2: Manage deprecated feature states as any other non-required
feature flags. This allows to execute an `is_feature_used()`
callback to determine if a deprecated feature can be denied. This
also allows to prevent the RabbitMQ node from starting if it
continues to use a deprecated feature.
V3: Manage deprecated feature states from the registry initialization
again. This is required because we need to know very early if some
of them are denied, so that an upgrade to a version of RabbitMQ
where a deprecated feature is disconnected or removed can be
performed.
To still prevent the start of a RabbitMQ node when a denied
deprecated feature is actively used, we run the `is_feature_used()`
callback of all denied deprecated features as part of the
`sync_cluster()` task. This task is executed as part of a feature
flag refresh executed when RabbitMQ starts or when plugins are
enabled. So even though a deprecated feature is marked as denied in
the registry early in the boot process, we will still abort the
start of a RabbitMQ node if the feature is used.
V4: Support context-dependent warnings. It is now possible to set a
specific message when deprecated feature is permitted, when it is
denied and when it is removed. Generic per-context messages are
still generated.
V5: Improve default warning messages, thanks to @pstack2021.
V6: Rename the configuration variable from `permit_deprecated_features.*`
to `deprecated_features.permit.*`. As @michaelklishin said, we tend
to use shorter top-level names.
2023-02-23 00:26:52 +08:00
|
|
|
end]).
|
|
|
|
|
|
|
|
end_per_testcase(_Testcase, Config) ->
|
|
|
|
rabbit_ct_helpers:run_steps(
|
|
|
|
Config,
|
|
|
|
[fun feature_flags_v2_SUITE:stop_slave_nodes/1]).
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%% Testcases.
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
|
|
|
use_unknown_deprecated_feature(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertNot(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assertNot(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
|
|
|
|
%% The node doesn't know about the deprecated feature and
|
|
|
|
%% thus rejects the request.
|
|
|
|
?assertEqual(
|
|
|
|
{error, unsupported},
|
|
|
|
rabbit_feature_flags:enable(FeatureName)),
|
|
|
|
?assertNot(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assertNot(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
use_deprecated_feature_permitted_by_default_everywhere(Config) ->
|
|
|
|
[FirstNode | _] = AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assertNot(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
ok = feature_flags_v2_SUITE:run_on_node(
|
|
|
|
FirstNode,
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
rabbit_feature_flags:enable(FeatureName)),
|
|
|
|
ok
|
|
|
|
end),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end )
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
use_deprecated_feature_denied_by_default_everywhere(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => denied_by_default}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
use_deprecated_feature_disconnected_everywhere(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => disconnected}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
use_deprecated_feature_removed_everywhere(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => removed}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
override_permitted_by_default_in_configuration(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default}},
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
application:set_env(
|
|
|
|
rabbit, permit_deprecated_features,
|
|
|
|
#{FeatureName => false}, [{persistent, false}])
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
override_denied_by_default_in_configuration(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => denied_by_default}},
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
application:set_env(
|
|
|
|
rabbit, permit_deprecated_features,
|
|
|
|
#{FeatureName => true}, [{persistent, false}])
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assertNot(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
override_disconnected_in_configuration(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => disconnected}},
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
application:set_env(
|
|
|
|
rabbit, permit_deprecated_features,
|
|
|
|
#{FeatureName => true}, [{persistent, false}])
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
override_removed_in_configuration(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => removed}},
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
application:set_env(
|
|
|
|
rabbit, permit_deprecated_features,
|
|
|
|
#{FeatureName => true}, [{persistent, false}])
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
has_is_feature_used_cb_returning_false(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => denied_by_default,
|
|
|
|
callbacks => #{is_feature_used =>
|
|
|
|
{?MODULE, feature_is_unused}}}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
feature_is_unused(_Args) ->
|
|
|
|
false.
|
|
|
|
|
|
|
|
has_is_feature_used_cb_returning_true(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => denied_by_default,
|
|
|
|
callbacks => #{is_feature_used =>
|
|
|
|
{?MODULE, feature_is_used}}}},
|
|
|
|
?assertEqual(
|
|
|
|
{error, {failed_to_deny_deprecated_features, [FeatureName]}},
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
%% The deprecated feature is marked as denied when the registry is
|
|
|
|
%% initialized/updated. It is the refresh that will return an error (the
|
|
|
|
%% one returned above).
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
feature_is_used(_Args) ->
|
|
|
|
true.
|
|
|
|
|
|
|
|
-define(MSGS, #{when_permitted => "permitted",
|
|
|
|
when_denied => "denied",
|
|
|
|
when_removed => "removed"}).
|
|
|
|
|
|
|
|
get_appropriate_warning_when_permitted(Config) ->
|
|
|
|
[FirstNode | _] = AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default,
|
|
|
|
messages => ?MSGS}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
?assertEqual(
|
|
|
|
maps:get(when_permitted, ?MSGS),
|
|
|
|
rabbit_deprecated_features:get_warning(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
ok = feature_flags_v2_SUITE:run_on_node(
|
|
|
|
FirstNode,
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
rabbit_feature_flags:enable(FeatureName)),
|
|
|
|
ok
|
|
|
|
end),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
?assertEqual(
|
|
|
|
maps:get(when_denied, ?MSGS),
|
|
|
|
rabbit_deprecated_features:get_warning(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
get_appropriate_warning_when_denied(Config) ->
|
|
|
|
[FirstNode | _] = AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => denied_by_default,
|
|
|
|
messages => ?MSGS}},
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
application:set_env(
|
|
|
|
rabbit, permit_deprecated_features,
|
|
|
|
#{FeatureName => true}, [{persistent, false}])
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
?assertEqual(
|
|
|
|
maps:get(when_permitted, ?MSGS),
|
|
|
|
rabbit_deprecated_features:get_warning(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
ok = feature_flags_v2_SUITE:run_on_node(
|
|
|
|
FirstNode,
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
rabbit_feature_flags:enable(FeatureName)),
|
|
|
|
ok
|
|
|
|
end),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
?assertEqual(
|
|
|
|
maps:get(when_denied, ?MSGS),
|
|
|
|
rabbit_deprecated_features:get_warning(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
get_appropriate_warning_when_disconnected(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => disconnected,
|
|
|
|
messages => ?MSGS}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
?assertEqual(
|
|
|
|
maps:get(when_removed, ?MSGS),
|
|
|
|
rabbit_deprecated_features:get_warning(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
|
|
|
|
|
|
|
get_appropriate_warning_when_removed(Config) ->
|
|
|
|
AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => disconnected,
|
|
|
|
messages => ?MSGS}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
?assertEqual(
|
|
|
|
maps:get(when_removed, ?MSGS),
|
|
|
|
rabbit_deprecated_features:get_warning(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes].
|
2023-07-17 23:59:55 +08:00
|
|
|
|
|
|
|
deprecated_feature_enabled_if_feature_flag_depends_on_it(Config) ->
|
|
|
|
[FirstNode | _] = AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default},
|
|
|
|
|
|
|
|
my_feature_flag =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
stability => experimental,
|
|
|
|
depends_on => [FeatureName]}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assertNot(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assert(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end)
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
ok = feature_flags_v2_SUITE:run_on_node(
|
|
|
|
FirstNode,
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
rabbit_feature_flags:enable(my_feature_flag)),
|
|
|
|
ok
|
|
|
|
end),
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(my_feature_flag)),
|
|
|
|
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end )
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
rabbit_ff_registry_factory:reset_registry()),
|
|
|
|
ok
|
|
|
|
end )
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
rabbit_ff_registry_factory:initialize_registry()),
|
|
|
|
ok
|
|
|
|
end )
|
|
|
|
|| Node <- AllNodes],
|
|
|
|
|
|
|
|
_ = [ok =
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
Node,
|
|
|
|
fun() ->
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(my_feature_flag)),
|
|
|
|
|
|
|
|
?assert(rabbit_feature_flags:is_supported(FeatureName)),
|
|
|
|
?assert(rabbit_feature_flags:is_enabled(FeatureName)),
|
|
|
|
?assertNot(
|
|
|
|
rabbit_deprecated_features:is_permitted(FeatureName)),
|
|
|
|
ok
|
|
|
|
end )
|
|
|
|
|| Node <- AllNodes].
|
2023-11-10 17:50:34 +08:00
|
|
|
|
|
|
|
list_all_deprecated_features(Config) ->
|
|
|
|
[FirstNode | _] = AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
FeatureName = ?FUNCTION_NAME,
|
|
|
|
FeatureFlags = #{FeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
FirstNode,
|
|
|
|
fun() ->
|
|
|
|
Map = rabbit_deprecated_features:list(all),
|
|
|
|
?assert(maps:is_key(FeatureName, Map))
|
|
|
|
end).
|
|
|
|
|
|
|
|
list_used_deprecated_features(Config) ->
|
|
|
|
[FirstNode | _] = AllNodes = ?config(nodes, Config),
|
|
|
|
feature_flags_v2_SUITE:connect_nodes(AllNodes),
|
|
|
|
feature_flags_v2_SUITE:override_running_nodes(AllNodes),
|
|
|
|
|
|
|
|
UsedFeatureName = used_deprecated_feature,
|
|
|
|
UnusedFeatureName = unused_deprecated_feature,
|
|
|
|
FeatureFlags = #{UsedFeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default,
|
|
|
|
callbacks => #{is_feature_used => {?MODULE, feature_is_used}}},
|
|
|
|
UnusedFeatureName =>
|
|
|
|
#{provided_by => rabbit,
|
|
|
|
deprecation_phase => permitted_by_default,
|
|
|
|
callbacks => #{is_feature_used => {?MODULE, feature_is_unused}}}},
|
|
|
|
?assertEqual(
|
|
|
|
ok,
|
|
|
|
feature_flags_v2_SUITE:inject_on_nodes(AllNodes, FeatureFlags)),
|
|
|
|
|
|
|
|
feature_flags_v2_SUITE:run_on_node(
|
|
|
|
FirstNode,
|
|
|
|
fun() ->
|
|
|
|
Map = rabbit_deprecated_features:list(used),
|
|
|
|
?assertNot(maps:is_key(UnusedFeatureName, Map)),
|
|
|
|
?assert(maps:is_key(UsedFeatureName, Map))
|
|
|
|
end).
|