diff --git a/apps/emqx_dashboard/test/emqx_dashboard_api_test_helpers.erl b/apps/emqx_dashboard/test/emqx_dashboard_api_test_helpers.erl index 572418346..a870e6280 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_api_test_helpers.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_api_test_helpers.erl @@ -25,6 +25,7 @@ request/3, request/4, request/5, + request/6, multipart_formdata_request/3, multipart_formdata_request/4, host/0, @@ -77,8 +78,11 @@ request(Username, Method, Url, Body) -> request(Username, <<"public">>, Method, Url, Body). request(Username, Password, Method, Url, Body) -> + request(Username, Password, Method, Url, Body, #{}). + +request(Username, Password, Method, Url, Body0, Headers) -> Request = - case Body of + case Body0 of [] when Method =:= get orelse Method =:= put orelse Method =:= head orelse Method =:= delete orelse @@ -86,8 +90,10 @@ request(Username, Password, Method, Url, Body) -> -> {Url, [auth_header(Username, Password)]}; _ -> - {Url, [auth_header(Username, Password)], "application/json", - emqx_utils_json:encode(Body)} + ContentType = maps:get("content-type", Headers, "application/json"), + HeadersList = maps:to_list(maps:without(["content-type"], Headers)), + Body = maybe_encode(Body0), + {Url, [auth_header(Username, Password) | HeadersList], ContentType, Body} end, ct:pal("Method: ~p, Request: ~p", [Method, Request]), case httpc:request(Method, Request, [], [{body_format, binary}]) of @@ -99,6 +105,9 @@ request(Username, Password, Method, Url, Body) -> {error, Reason} end. +maybe_encode(Body) when is_binary(Body) -> Body; +maybe_encode(Body) -> emqx_utils_json:encode(Body). + host() -> ?HOST. diff --git a/apps/emqx_license/src/emqx_license_checker.erl b/apps/emqx_license/src/emqx_license_checker.erl index 5d8393037..fcfac47c3 100644 --- a/apps/emqx_license/src/emqx_license_checker.erl +++ b/apps/emqx_license/src/emqx_license_checker.erl @@ -119,7 +119,11 @@ handle_call({update, License}, _From, #{license := Old} = State) -> ok = log_new_license(Old, License), {reply, check_license(License), State1#{license => License}}; handle_call(dump, _From, #{license := License} = State) -> - {reply, emqx_license_parser:dump(License), State}; + Dump0 = emqx_license_parser:dump(License), + %% resolve the current dynamic limit + MaybeDynamic = get_max_connections(License), + Dump = lists:keyreplace(max_connections, 1, Dump0, {max_connections, MaybeDynamic}), + {reply, Dump, State}; handle_call(expiry_epoch, _From, #{license := License} = State) -> ExpiryEpoch = date_to_expiry_epoch(emqx_license_parser:expiry_date(License)), {reply, ExpiryEpoch, State}; diff --git a/apps/emqx_license/src/emqx_license_http_api.erl b/apps/emqx_license/src/emqx_license_http_api.erl index 4d869f840..31d185651 100644 --- a/apps/emqx_license/src/emqx_license_http_api.erl +++ b/apps/emqx_license/src/emqx_license_http_api.erl @@ -149,7 +149,7 @@ error_msg(Code, Msg) -> '/license/setting'(get, _Params) -> {200, get_setting()}; '/license/setting'(put, #{body := Setting}) -> - case emqx_license:update_setting(Setting) of + case update_setting(Setting) of {error, Error} -> ?SLOG( error, @@ -165,6 +165,12 @@ error_msg(Code, Msg) -> '/license/setting'(get, undefined) end. +update_setting(Setting) when is_map(Setting) -> + emqx_license:update_setting(Setting); +update_setting(_Setting) -> + %% TODO: EMQX-12401 content-type enforcement by framework + {error, "bad content-type"}. + fields(key_license) -> [lists:keyfind(key, 1, emqx_license_schema:fields(key_license))]. diff --git a/apps/emqx_license/test/emqx_license_http_api_SUITE.erl b/apps/emqx_license/test/emqx_license_http_api_SUITE.erl index b64a4d5af..380930527 100644 --- a/apps/emqx_license/test/emqx_license_http_api_SUITE.erl +++ b/apps/emqx_license/test/emqx_license_http_api_SUITE.erl @@ -57,7 +57,12 @@ end_per_testcase(_TestCase, _Config) -> %%------------------------------------------------------------------------------ request(Method, Uri, Body) -> - emqx_dashboard_api_test_helpers:request(<<"license_admin">>, Method, Uri, Body). + request(Method, Uri, Body, #{}). + +request(Method, Uri, Body, Headers) -> + emqx_dashboard_api_test_helpers:request( + <<"license_admin">>, <<"public">>, Method, Uri, Body, Headers + ). uri(Segments) -> emqx_dashboard_api_test_helpers:uri(Segments). @@ -229,24 +234,44 @@ t_license_setting(_Config) -> t_license_setting_bc(_Config) -> %% Create a BC license - Key = emqx_license_test_lib:make_license(#{customer_type => "3"}), + Key = emqx_license_test_lib:make_license(#{ + customer_type => "3", + max_connections => "33" + }), Res = request(post, uri(["license"]), #{key => Key}), ?assertMatch({ok, 200, _}, Res), + %% for bc customer, before setting dynamic limit, + %% the default limit is always 25, as if no license + ?assertMatch(#{<<"max_connections">> := 25}, request_dump()), %% get GetRes = request(get, uri(["license", "setting"]), []), + %% aslo check that the settings return correctly validate_setting(GetRes, <<"75%">>, <<"80%">>, 25), %% update Low = <<"50%">>, High = <<"55%">>, - UpdateRes = request(put, uri(["license", "setting"]), #{ + Settings = #{ <<"connection_low_watermark">> => Low, <<"connection_high_watermark">> => High, <<"dynamic_max_connections">> => 26 - }), + }, + UpdateRes = request(put, uri(["license", "setting"]), Settings), + %% assert it's changed to 26 validate_setting(UpdateRes, Low, High, 26), + ?assertMatch(#{<<"max_connections">> := 26}, request_dump()), ?assertEqual(26, emqx_config:get([license, dynamic_max_connections])), + %% Try to set it beyond the limit, it's allowed, but no effect + Settings2 = Settings#{<<"dynamic_max_connections">> => 99999}, + UpdateRes2 = request(put, uri(["license", "setting"]), Settings2), + validate_setting(UpdateRes2, Low, High, 99999), + ?assertMatch(#{<<"max_connections">> := 33}, request_dump()), + ?assertEqual(99999, emqx_config:get([license, dynamic_max_connections])), ok. +request_dump() -> + {ok, 200, DumpJson} = request(get, uri(["license"]), []), + emqx_utils_json:decode(DumpJson). + validate_setting(Res, ExpectLow, ExpectHigh) -> ?assertMatch({ok, 200, _}, Res), {ok, 200, Payload} = Res,