emqx_config_handler_SUITE.erl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2019-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_config_handler_SUITE).
  17. -compile(export_all).
  18. -compile(nowarn_export_all).
  19. -define(MOD, '$mod').
  20. -define(WKEY, '?').
  21. -define(CLUSTER_CONF, "/tmp/cluster.conf").
  22. -include_lib("eunit/include/eunit.hrl").
  23. -include_lib("common_test/include/ct.hrl").
  24. all() -> emqx_common_test_helpers:all(?MODULE).
  25. init_per_suite(Config) ->
  26. emqx_common_test_helpers:boot_modules(all),
  27. emqx_common_test_helpers:start_apps([]),
  28. Config.
  29. end_per_suite(_Config) ->
  30. emqx_common_test_helpers:stop_apps([]).
  31. init_per_testcase(_Case, Config) ->
  32. _ = file:delete(?CLUSTER_CONF),
  33. Config.
  34. end_per_testcase(_Case, _Config) ->
  35. ok.
  36. t_handler(_Config) ->
  37. BadCallBackMod = emqx,
  38. RootKey = sysmon,
  39. %% bad
  40. ?assertError(
  41. #{msg := "bad_emqx_config_handler_callback", module := BadCallBackMod},
  42. emqx_config_handler:add_handler([RootKey], BadCallBackMod)
  43. ),
  44. %% simple
  45. ok = emqx_config_handler:add_handler([RootKey], ?MODULE),
  46. #{handlers := Handlers0} = emqx_config_handler:info(),
  47. ?assertMatch(#{RootKey := #{?MOD := ?MODULE}}, Handlers0),
  48. ok = emqx_config_handler:remove_handler([RootKey]),
  49. #{handlers := Handlers1} = emqx_config_handler:info(),
  50. ct:pal("Key:~p simple: ~p~n", [RootKey, Handlers1]),
  51. ?assertEqual(false, maps:is_key(RootKey, Handlers1)),
  52. %% wildcard 1
  53. Wildcard1 = [RootKey, '?', cpu_check_interval],
  54. ok = emqx_config_handler:add_handler(Wildcard1, ?MODULE),
  55. #{handlers := Handlers2} = emqx_config_handler:info(),
  56. ?assertMatch(#{RootKey := #{?WKEY := #{cpu_check_interval := #{?MOD := ?MODULE}}}}, Handlers2),
  57. ok = emqx_config_handler:remove_handler(Wildcard1),
  58. #{handlers := Handlers3} = emqx_config_handler:info(),
  59. ct:pal("Key:~p wildcard1: ~p~n", [Wildcard1, Handlers3]),
  60. ?assertEqual(false, maps:is_key(RootKey, Handlers3)),
  61. %% can_override_a_wildcard_path
  62. ok = emqx_config_handler:add_handler(Wildcard1, ?MODULE),
  63. ?assertEqual(ok, emqx_config_handler:add_handler([RootKey, os, cpu_check_interval], ?MODULE)),
  64. ok = emqx_config_handler:remove_handler(Wildcard1),
  65. ok = emqx_config_handler:remove_handler([RootKey, os, cpu_check_interval]),
  66. ok = emqx_config_handler:add_handler([RootKey, os, cpu_check_interval], ?MODULE),
  67. ok = emqx_config_handler:add_handler(Wildcard1, ?MODULE),
  68. ok = emqx_config_handler:remove_handler([RootKey, os, cpu_check_interval]),
  69. ok = emqx_config_handler:remove_handler(Wildcard1),
  70. ok.
  71. t_conflict_handler(_Config) ->
  72. ok = emqx_config_handler:add_handler([sysmon, '?', '?'], ?MODULE),
  73. ?assertMatch(
  74. {error, {conflict, _}},
  75. emqx_config_handler:add_handler([sysmon, '?', cpu_check_interval], ?MODULE)
  76. ),
  77. ok = emqx_config_handler:remove_handler([sysmon, '?', '?']),
  78. ok = emqx_config_handler:add_handler([sysmon, '?', cpu_check_interval], ?MODULE),
  79. ?assertMatch(
  80. {error, {conflict, _}},
  81. emqx_config_handler:add_handler([sysmon, '?', '?'], ?MODULE)
  82. ),
  83. ok = emqx_config_handler:remove_handler([sysmon, '?', cpu_check_interval]),
  84. %% override
  85. ok = emqx_config_handler:add_handler([sysmon], emqx_config_logger),
  86. ?assertMatch(
  87. #{handlers := #{sysmon := #{?MOD := emqx_config_logger}}},
  88. emqx_config_handler:info()
  89. ),
  90. ok.
  91. t_root_key_update(_Config) ->
  92. PathKey = [sysmon],
  93. Opts = #{rawconf_with_defaults => true},
  94. ok = emqx_config_handler:add_handler(PathKey, ?MODULE),
  95. %% update
  96. Old = #{<<"os">> := OS} = emqx:get_raw_config(PathKey),
  97. {ok, Res} = emqx:update_config(
  98. PathKey,
  99. Old#{<<"os">> => OS#{<<"cpu_check_interval">> => <<"12s">>}},
  100. Opts
  101. ),
  102. ?assertMatch(
  103. #{
  104. config := #{os := #{cpu_check_interval := 12000}},
  105. post_config_update := #{?MODULE := ok},
  106. raw_config := #{<<"os">> := #{<<"cpu_check_interval">> := <<"12s">>}}
  107. },
  108. Res
  109. ),
  110. ?assertMatch(#{os := #{cpu_check_interval := 12000}}, emqx:get_config(PathKey)),
  111. %% update sub key
  112. SubKey = PathKey ++ [os, cpu_high_watermark],
  113. ?assertEqual(
  114. {ok, #{
  115. config => 0.81,
  116. post_config_update => #{},
  117. raw_config => <<"81%">>
  118. }},
  119. emqx:update_config(SubKey, "81%", Opts)
  120. ),
  121. ?assertEqual(0.81, emqx:get_config(SubKey)),
  122. ?assertEqual("81%", emqx:get_raw_config(SubKey)),
  123. %% remove
  124. ?assertEqual({error, "remove_root_is_forbidden"}, emqx:remove_config(PathKey)),
  125. ?assertMatch(true, is_map(emqx:get_raw_config(PathKey))),
  126. ok = emqx_config_handler:remove_handler(PathKey),
  127. ok.
  128. t_sub_key_update_remove(_Config) ->
  129. KeyPath = [sysmon, os, cpu_check_interval],
  130. Opts = #{},
  131. ok = emqx_config_handler:add_handler(KeyPath, ?MODULE),
  132. {ok, Res} = emqx:update_config(KeyPath, <<"60s">>, Opts),
  133. ?assertMatch(
  134. #{
  135. config := 60000,
  136. post_config_update := #{?MODULE := ok},
  137. raw_config := <<"60s">>
  138. },
  139. Res
  140. ),
  141. ?assertMatch(60000, emqx:get_config(KeyPath)),
  142. KeyPath2 = [sysmon, os, cpu_low_watermark],
  143. ok = emqx_config_handler:add_handler(KeyPath2, ?MODULE),
  144. {ok, Res1} = emqx:update_config(KeyPath2, <<"40%">>, Opts),
  145. ?assertMatch(
  146. #{
  147. config := 0.4,
  148. post_config_update := #{},
  149. raw_config := <<"40%">>
  150. },
  151. Res1
  152. ),
  153. ?assertMatch(0.4, emqx:get_config(KeyPath2)),
  154. %% remove
  155. ?assertEqual(
  156. {ok, #{post_config_update => #{?MODULE => ok}}},
  157. emqx:remove_config(KeyPath)
  158. ),
  159. ?assertError(
  160. {config_not_found, [<<"sysmon">>, os, cpu_check_interval]}, emqx:get_raw_config(KeyPath)
  161. ),
  162. OSKey = maps:keys(emqx:get_raw_config([sysmon, os])),
  163. ?assertEqual(false, lists:member(<<"cpu_check_interval">>, OSKey)),
  164. ?assert(length(OSKey) > 0),
  165. ok = emqx_config_handler:remove_handler(KeyPath),
  166. ok = emqx_config_handler:remove_handler(KeyPath2),
  167. ok.
  168. t_check_failed(_Config) ->
  169. KeyPath = [sysmon, os, cpu_check_interval],
  170. Opts = #{rawconf_with_defaults => true},
  171. Origin = emqx:get_raw_config(KeyPath),
  172. ok = emqx_config_handler:add_handler(KeyPath, ?MODULE),
  173. %% It should be a duration("1h"), but we set it as a percent.
  174. ?assertMatch({error, _Res}, emqx:update_config(KeyPath, <<"80%">>, Opts)),
  175. New = emqx:get_raw_config(KeyPath),
  176. ?assertEqual(Origin, New),
  177. ok = emqx_config_handler:remove_handler(KeyPath),
  178. ok.
  179. t_stop(_Config) ->
  180. OldPid = erlang:whereis(emqx_config_handler),
  181. OldInfo = emqx_config_handler:info(),
  182. emqx_config_handler:stop(),
  183. NewPid = wait_for_new_pid(),
  184. NewInfo = emqx_config_handler:info(),
  185. ?assertNotEqual(OldPid, NewPid),
  186. ?assertEqual(OldInfo, NewInfo),
  187. ok.
  188. t_callback_crash(_Config) ->
  189. CrashPath = [sysmon, os, procmem_high_watermark],
  190. Opts = #{rawconf_with_defaults => true},
  191. ok = emqx_config_handler:add_handler(CrashPath, ?MODULE),
  192. Old = emqx:get_raw_config(CrashPath),
  193. ?assertMatch(
  194. {error, {config_update_crashed, _}}, emqx:update_config(CrashPath, <<"89%">>, Opts)
  195. ),
  196. New = emqx:get_raw_config(CrashPath),
  197. ?assertEqual(Old, New),
  198. ok = emqx_config_handler:remove_handler(CrashPath),
  199. ok.
  200. t_pre_callback_error(_Config) ->
  201. callback_error(
  202. [sysmon, os, mem_check_interval],
  203. <<"100s">>,
  204. {error, {pre_config_update, ?MODULE, pre_config_update_error}}
  205. ),
  206. ok.
  207. t_post_update_error(_Config) ->
  208. callback_error(
  209. [sysmon, os, sysmem_high_watermark],
  210. <<"60%">>,
  211. {error, {post_config_update, ?MODULE, post_config_update_error}}
  212. ),
  213. ok.
  214. t_handler_root() ->
  215. %% Don't rely on default emqx_config_handler's merge behaviour.
  216. RootKey = [],
  217. Opts = #{rawconf_with_defaults => true},
  218. ok = emqx_config_handler:add_handler(RootKey, ?MODULE),
  219. %% update
  220. Old = #{<<"sysmon">> := #{<<"os">> := OS}} = emqx:get_raw_config(RootKey),
  221. {ok, Res} = emqx:update_config(
  222. RootKey,
  223. Old#{<<"sysmon">> => #{<<"os">> => OS#{<<"cpu_check_interval">> => <<"12s">>}}},
  224. Opts
  225. ),
  226. ?assertMatch(
  227. #{
  228. config := #{os := #{cpu_check_interval := 12000}},
  229. post_config_update := #{?MODULE := ok},
  230. raw_config := #{<<"os">> := #{<<"cpu_check_interval">> := <<"12s">>}}
  231. },
  232. Res
  233. ),
  234. ?assertMatch(#{sysmon := #{os := #{cpu_check_interval := 12000}}}, emqx:get_config(RootKey)),
  235. ok = emqx_config_handler:remove_handler(RootKey),
  236. ok.
  237. t_get_raw_cluster_override_conf(_Config) ->
  238. Raw0 = emqx_config:read_override_conf(#{override_to => cluster}),
  239. Raw1 = emqx_config_handler:get_raw_cluster_override_conf(),
  240. ?assertEqual(Raw0, Raw1),
  241. OldPid = erlang:whereis(emqx_config_handler),
  242. OldInfo = emqx_config_handler:info(),
  243. ?assertEqual(ok, gen_server:call(emqx_config_handler, bad_call_msg)),
  244. gen_server:cast(emqx_config_handler, bad_cast_msg),
  245. erlang:send(emqx_config_handler, bad_info_msg),
  246. NewPid = erlang:whereis(emqx_config_handler),
  247. NewInfo = emqx_config_handler:info(),
  248. ?assertEqual(OldPid, NewPid),
  249. ?assertEqual(OldInfo, NewInfo),
  250. ok.
  251. pre_config_update([sysmon], UpdateReq, _RawConf) ->
  252. {ok, UpdateReq};
  253. pre_config_update([sysmon, os], UpdateReq, _RawConf) ->
  254. {ok, UpdateReq};
  255. pre_config_update([sysmon, os, cpu_check_interval], UpdateReq, _RawConf) ->
  256. {ok, UpdateReq};
  257. pre_config_update([sysmon, os, cpu_low_watermark], UpdateReq, _RawConf) ->
  258. {ok, UpdateReq};
  259. pre_config_update([sysmon, os, cpu_high_watermark], UpdateReq, _RawConf) ->
  260. {ok, UpdateReq};
  261. pre_config_update([sysmon, os, sysmem_high_watermark], UpdateReq, _RawConf) ->
  262. {ok, UpdateReq};
  263. pre_config_update([sysmon, os, mem_check_interval], _UpdateReq, _RawConf) ->
  264. {error, pre_config_update_error}.
  265. post_config_update([sysmon], _UpdateReq, _NewConf, _OldConf, _AppEnvs) ->
  266. {ok, ok};
  267. post_config_update([sysmon, os], _UpdateReq, _NewConf, _OldConf, _AppEnvs) ->
  268. {ok, ok};
  269. post_config_update([sysmon, os, cpu_check_interval], _UpdateReq, _NewConf, _OldConf, _AppEnvs) ->
  270. {ok, ok};
  271. post_config_update([sysmon, os, cpu_low_watermark], _UpdateReq, _NewConf, _OldConf, _AppEnvs) ->
  272. ok;
  273. post_config_update([sysmon, os, cpu_high_watermark], _UpdateReq, _NewConf, _OldConf, _AppEnvs) ->
  274. ok;
  275. post_config_update([sysmon, os, sysmem_high_watermark], _UpdateReq, _NewConf, _OldConf, _AppEnvs) ->
  276. {error, post_config_update_error}.
  277. wait_for_new_pid() ->
  278. case erlang:whereis(emqx_config_handler) of
  279. undefined ->
  280. ct:sleep(10),
  281. wait_for_new_pid();
  282. Pid ->
  283. Pid
  284. end.
  285. callback_error(FailedPath, Update, ExpectError) ->
  286. Opts = #{rawconf_with_defaults => true},
  287. ok = emqx_config_handler:add_handler(FailedPath, ?MODULE),
  288. Old = emqx:get_raw_config(FailedPath, undefined),
  289. Error = emqx:update_config(FailedPath, Update, Opts),
  290. case ExpectError of
  291. {error, {post_config_update, ?MODULE, post_config_update_error}} ->
  292. ?assertMatch(
  293. {error, {post_config_update, ?MODULE, {post_config_update_error, _}}}, Error
  294. );
  295. _ ->
  296. ?assertEqual(ExpectError, Error)
  297. end,
  298. New = emqx:get_raw_config(FailedPath, undefined),
  299. ?assertEqual(Old, New),
  300. ok = emqx_config_handler:remove_handler(FailedPath),
  301. ok.