فهرست منبع

test(config): default zone and global defaults

William Yang 2 سال پیش
والد
کامیت
a2f8e87389
3فایلهای تغییر یافته به همراه408 افزوده شده و 2 حذف شده
  1. 1 1
      .github/workflows/run_emqx_app_tests.yaml
  2. 1 1
      apps/emqx/src/emqx_config.erl
  3. 406 0
      apps/emqx/test/emqx_config_SUITE.erl

+ 1 - 1
.github/workflows/run_emqx_app_tests.yaml

@@ -76,5 +76,5 @@ jobs:
     - uses: actions/upload-artifact@v3
       if: failure()
       with:
-        name: logs
+        name: logs-${{ matrix.runs-on }}
         path: apps/emqx/_build/test/logs

+ 1 - 1
apps/emqx/src/emqx_config.erl

@@ -855,4 +855,4 @@ maybe_update_zone([RootName | _T] = Path, Value) ->
 
 -spec zone_roots() -> [atom()].
 zone_roots() ->
-    lists:map(fun atom/1, emqx_zone_schema:roots()).
+    lists:map(fun list_to_atom/1, emqx_zone_schema:roots()).

+ 406 - 0
apps/emqx/test/emqx_config_SUITE.erl

@@ -19,6 +19,7 @@
 -compile(export_all).
 -compile(nowarn_export_all).
 -include_lib("eunit/include/eunit.hrl").
+-include_lib("common_test/include/ct.hrl").
 -include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
 all() -> emqx_common_test_helpers:all(?MODULE).
@@ -96,3 +97,408 @@ t_unknown_rook_keys(_) ->
         end
     ),
     ok.
+
+t_init_load_emqx_schema(Config) ->
+    emqx_config:erase_all(),
+    %% Given empty config file
+    ConfFile = prepare_conf_file(?FUNCTION_NAME, <<"">>, Config),
+    application:set_env(emqx, config_files, [ConfFile]),
+    %% When load emqx_schema
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    %% Then default zone is injected with all global defaults
+    Default = emqx_config:get([zones, default]),
+    ?assertMatch(
+        #{
+            mqtt := _,
+            stats := _,
+            flapping_detect := _,
+            force_shutdown := _,
+            conn_congestion := _,
+            force_gc := _,
+            overload_protection := _
+        },
+        Default
+    ).
+
+t_init_zones_load_emqx_schema_no_default(Config) ->
+    emqx_config:erase_all(),
+    %% Given empty config file
+    ConfFile = prepare_conf_file(?FUNCTION_NAME, <<"">>, Config),
+    application:set_env(emqx, config_files, [ConfFile]),
+    %% When load emqx_schema
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    %% Then read for none existing zone should throw error
+    ?assertError(
+        {config_not_found, [zones, no_exists]},
+        emqx_config:get([zones, no_exists])
+    ).
+
+t_init_zones_load_other_schema(Config) ->
+    emqx_config:erase_all(),
+    %% Given empty config file
+    ConfFile = prepare_conf_file(?FUNCTION_NAME, <<"">>, Config),
+    application:set_env(emqx, config_files, [ConfFile]),
+    %% When load schema other than emqx_schema
+    %% Then load should success
+    ?assertEqual(ok, emqx_config:init_load(emqx_limiter_schema)),
+    %% Then no default zone is loaded.
+    ?assertError(
+        {config_not_found, [zones, default]},
+        emqx_config:get([zones, default])
+    ).
+
+t_init_zones_with_user_defined_default_zone(Config) ->
+    emqx_config:erase_all(),
+    %% Given user defined config for default zone
+    ConfFile = prepare_conf_file(
+        ?FUNCTION_NAME, <<"zones.default.mqtt.max_topic_alias=1024">>, Config
+    ),
+    application:set_env(emqx, config_files, [ConfFile]),
+    %% When load schema
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    %% Then user defined value is set and others are defaults
+
+    ?assertMatch(
+        #{
+            conn_congestion :=
+                #{enable_alarm := true, min_alarm_sustain_duration := 60000},
+            flapping_detect :=
+                #{ban_time := 300000, max_count := 15, window_time := disabled},
+            force_gc :=
+                #{bytes := 16777216, count := 16000, enable := true},
+            force_shutdown :=
+                #{
+                    enable := true,
+                    max_heap_size := 4194304,
+                    max_mailbox_size := 1000
+                },
+            mqtt :=
+                #{
+                    await_rel_timeout := 300000,
+                    exclusive_subscription := false,
+                    idle_timeout := 15000,
+                    ignore_loop_deliver := false,
+                    keepalive_backoff := 0.75,
+                    keepalive_multiplier := 1.5,
+                    max_awaiting_rel := 100,
+                    max_clientid_len := 65535,
+                    max_inflight := 32,
+                    max_mqueue_len := 1000,
+                    max_packet_size := 1048576,
+                    max_qos_allowed := 2,
+                    max_subscriptions := infinity,
+                    %% <=== here!
+                    max_topic_alias := 1024,
+                    max_topic_levels := 128,
+                    mqueue_default_priority := lowest,
+                    mqueue_priorities := disabled,
+                    mqueue_store_qos0 := true,
+                    peer_cert_as_clientid := disabled,
+                    peer_cert_as_username := disabled,
+                    response_information := [],
+                    retain_available := true,
+                    retry_interval := 30000,
+                    server_keepalive := disabled,
+                    session_expiry_interval := 7200000,
+                    shared_subscription := true,
+                    strict_mode := false,
+                    upgrade_qos := false,
+                    use_username_as_clientid := false,
+                    wildcard_subscription := true
+                },
+            overload_protection :=
+                #{
+                    backoff_delay := 1,
+                    backoff_gc := false,
+                    backoff_hibernation := true,
+                    backoff_new_conn := true,
+                    enable := false
+                },
+            stats := #{enable := true}
+        },
+        emqx_config:get([zones, default])
+    ).
+
+t_init_zones_with_user_defined_other_zone(Config) ->
+    emqx_config:erase_all(),
+    %% Given user defined config for default zone
+    ConfFile = prepare_conf_file(
+        ?FUNCTION_NAME, <<"zones.myzone.mqtt.max_topic_alias=1024">>, Config
+    ),
+    application:set_env(emqx, config_files, [ConfFile]),
+    %% When load schema
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    %% Then user defined value is set and others are defaults
+    ?assertMatch(
+        #{
+            conn_congestion :=
+                #{enable_alarm := true, min_alarm_sustain_duration := 60000},
+            flapping_detect :=
+                #{ban_time := 300000, max_count := 15, window_time := disabled},
+            force_gc :=
+                #{bytes := 16777216, count := 16000, enable := true},
+            force_shutdown :=
+                #{
+                    enable := true,
+                    max_heap_size := 4194304,
+                    max_mailbox_size := 1000
+                },
+            mqtt :=
+                #{
+                    await_rel_timeout := 300000,
+                    exclusive_subscription := false,
+                    idle_timeout := 15000,
+                    ignore_loop_deliver := false,
+                    keepalive_backoff := 0.75,
+                    keepalive_multiplier := 1.5,
+                    max_awaiting_rel := 100,
+                    max_clientid_len := 65535,
+                    max_inflight := 32,
+                    max_mqueue_len := 1000,
+                    max_packet_size := 1048576,
+                    max_qos_allowed := 2,
+                    max_subscriptions := infinity,
+                    %% <=== here!
+                    max_topic_alias := 1024,
+                    max_topic_levels := 128,
+                    mqueue_default_priority := lowest,
+                    mqueue_priorities := disabled,
+                    mqueue_store_qos0 := true,
+                    peer_cert_as_clientid := disabled,
+                    peer_cert_as_username := disabled,
+                    response_information := [],
+                    retain_available := true,
+                    retry_interval := 30000,
+                    server_keepalive := disabled,
+                    session_expiry_interval := 7200000,
+                    shared_subscription := true,
+                    strict_mode := false,
+                    upgrade_qos := false,
+                    use_username_as_clientid := false,
+                    wildcard_subscription := true
+                },
+            overload_protection :=
+                #{
+                    backoff_delay := 1,
+                    backoff_gc := false,
+                    backoff_hibernation := true,
+                    backoff_new_conn := true,
+                    enable := false
+                },
+            stats := #{enable := true}
+        },
+        emqx_config:get([zones, myzone])
+    ),
+
+    %% Then default zone still have the defaults
+    ?assertMatch(
+        #{
+            conn_congestion :=
+                #{enable_alarm := true, min_alarm_sustain_duration := 60000},
+            flapping_detect :=
+                #{ban_time := 300000, max_count := 15, window_time := disabled},
+            force_gc :=
+                #{bytes := 16777216, count := 16000, enable := true},
+            force_shutdown :=
+                #{
+                    enable := true,
+                    max_heap_size := 4194304,
+                    max_mailbox_size := 1000
+                },
+            mqtt :=
+                #{
+                    await_rel_timeout := 300000,
+                    exclusive_subscription := false,
+                    idle_timeout := 15000,
+                    ignore_loop_deliver := false,
+                    keepalive_backoff := 0.75,
+                    keepalive_multiplier := 1.5,
+                    max_awaiting_rel := 100,
+                    max_clientid_len := 65535,
+                    max_inflight := 32,
+                    max_mqueue_len := 1000,
+                    max_packet_size := 1048576,
+                    max_qos_allowed := 2,
+                    max_subscriptions := infinity,
+                    max_topic_alias := 65535,
+                    max_topic_levels := 128,
+                    mqueue_default_priority := lowest,
+                    mqueue_priorities := disabled,
+                    mqueue_store_qos0 := true,
+                    peer_cert_as_clientid := disabled,
+                    peer_cert_as_username := disabled,
+                    response_information := [],
+                    retain_available := true,
+                    retry_interval := 30000,
+                    server_keepalive := disabled,
+                    session_expiry_interval := 7200000,
+                    shared_subscription := true,
+                    strict_mode := false,
+                    upgrade_qos := false,
+                    use_username_as_clientid := false,
+                    wildcard_subscription := true
+                },
+            overload_protection :=
+                #{
+                    backoff_delay := 1,
+                    backoff_gc := false,
+                    backoff_hibernation := true,
+                    backoff_new_conn := true,
+                    enable := false
+                },
+            stats := #{enable := true}
+        },
+        emqx_config:get([zones, default])
+    ).
+
+t_init_zones_with_cust_root_mqtt(Config) ->
+    emqx_config:erase_all(),
+    %% Given user defined non default mqtt schema in config file
+    ConfFile = prepare_conf_file(?FUNCTION_NAME, <<"mqtt.retry_interval=600000">>, Config),
+    application:set_env(emqx, config_files, [ConfFile]),
+    %% When emqx_schema is loaded
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    %% Then the value is reflected in default `zone' and other fields under mqtt are default.
+    ?assertMatch(
+        #{
+            await_rel_timeout := 300000,
+            exclusive_subscription := false,
+            idle_timeout := 15000,
+            ignore_loop_deliver := false,
+            keepalive_backoff := 0.75,
+            keepalive_multiplier := 1.5,
+            max_awaiting_rel := 100,
+            max_clientid_len := 65535,
+            max_inflight := 32,
+            max_mqueue_len := 1000,
+            max_packet_size := 1048576,
+            max_qos_allowed := 2,
+            max_subscriptions := infinity,
+            max_topic_alias := 65535,
+            max_topic_levels := 128,
+            mqueue_default_priority := lowest,
+            mqueue_priorities := disabled,
+            mqueue_store_qos0 := true,
+            peer_cert_as_clientid := disabled,
+            peer_cert_as_username := disabled,
+            response_information := [],
+            retain_available := true,
+            %% <=== here
+            retry_interval := 600000,
+            server_keepalive := disabled,
+            session_expiry_interval := 7200000,
+            shared_subscription := true,
+            strict_mode := false,
+            upgrade_qos := false,
+            use_username_as_clientid := false,
+            wildcard_subscription := true
+        },
+        emqx_config:get([zones, default, mqtt])
+    ).
+
+t_default_zone_is_updated_after_global_defaults_updated(Config) ->
+    emqx_config:erase_all(),
+    %% Given user defined non default mqtt schema in config file
+    ConfFile = prepare_conf_file(?FUNCTION_NAME, <<"">>, Config),
+    application:set_env(emqx, config_files, [ConfFile]),
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    ?assertNotEqual(900000, emqx_config:get([zones, default, mqtt, retry_interval])),
+    %% When emqx_schema is loaded
+    emqx_config:put([mqtt, retry_interval], 900000),
+    %% Then the value is reflected in default `zone' and other fields under mqtt are default.
+    ?assertMatch(
+        #{
+            await_rel_timeout := 300000,
+            exclusive_subscription := false,
+            idle_timeout := 15000,
+            ignore_loop_deliver := false,
+            keepalive_backoff := 0.75,
+            keepalive_multiplier := 1.5,
+            max_awaiting_rel := 100,
+            max_clientid_len := 65535,
+            max_inflight := 32,
+            max_mqueue_len := 1000,
+            max_packet_size := 1048576,
+            max_qos_allowed := 2,
+            max_subscriptions := infinity,
+            max_topic_alias := 65535,
+            max_topic_levels := 128,
+            mqueue_default_priority := lowest,
+            mqueue_priorities := disabled,
+            mqueue_store_qos0 := true,
+            peer_cert_as_clientid := disabled,
+            peer_cert_as_username := disabled,
+            response_information := [],
+            retain_available := true,
+            %% <=== here
+            retry_interval := 900000,
+            server_keepalive := disabled,
+            session_expiry_interval := 7200000,
+            shared_subscription := true,
+            strict_mode := false,
+            upgrade_qos := false,
+            use_username_as_clientid := false,
+            wildcard_subscription := true
+        },
+        emqx_config:get([zones, default, mqtt])
+    ).
+
+t_other_zone_is_updated_after_global_defaults_updated(Config) ->
+    emqx_config:erase_all(),
+    %% Given user defined non default mqtt schema in config file
+    ConfFile = prepare_conf_file(?FUNCTION_NAME, <<"zones.myzone.mqtt.max_inflight=32">>, Config),
+    application:set_env(emqx, config_files, [ConfFile]),
+    ?assertEqual(ok, emqx_config:init_load(emqx_schema)),
+    ?assertNotEqual(900000, emqx_config:get([zones, myzone, mqtt, retry_interval])),
+    %% When emqx_schema is loaded
+    emqx_config:put([mqtt, retry_interval], 900000),
+    %% Then the value is reflected in default `zone' and other fields under mqtt are default.
+    ?assertMatch(
+        #{
+            await_rel_timeout := 300000,
+            exclusive_subscription := false,
+            idle_timeout := 15000,
+            ignore_loop_deliver := false,
+            keepalive_backoff := 0.75,
+            keepalive_multiplier := 1.5,
+            max_awaiting_rel := 100,
+            max_clientid_len := 65535,
+            max_inflight := 32,
+            max_mqueue_len := 1000,
+            max_packet_size := 1048576,
+            max_qos_allowed := 2,
+            max_subscriptions := infinity,
+            max_topic_alias := 65535,
+            max_topic_levels := 128,
+            mqueue_default_priority := lowest,
+            mqueue_priorities := disabled,
+            mqueue_store_qos0 := true,
+            peer_cert_as_clientid := disabled,
+            peer_cert_as_username := disabled,
+            response_information := [],
+            retain_available := true,
+            %% <=== here
+            retry_interval := 900000,
+            server_keepalive := disabled,
+            session_expiry_interval := 7200000,
+            shared_subscription := true,
+            strict_mode := false,
+            upgrade_qos := false,
+            use_username_as_clientid := false,
+            wildcard_subscription := true
+        },
+        emqx_config:get([zones, myzone, mqtt])
+    ).
+
+%%%
+%%% Helpers
+%%%
+prepare_conf_file(Name, Content, CTConfig) ->
+    Filename = tc_conf_file(Name, CTConfig),
+    filelib:ensure_dir(Filename),
+    ok = file:write_file(Filename, Content),
+    Filename.
+
+tc_conf_file(TC, Config) ->
+    DataDir = ?config(data_dir, Config),
+    filename:join([DataDir, TC, 'emqx.conf']).