Skip to content

Commit 0c90b33

Browse files
authored
Merge pull request #259 from emqx/fix-default-integer-not-from-string
fix: builtin type don't convert from_string when value is integer
2 parents fad34ad + 472711f commit 0c90b33

File tree

4 files changed

+131
-15
lines changed

4 files changed

+131
-15
lines changed

sample-schemas/emqx_management_schema.erl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
-behaviour(hocon_schema).
66

7-
-type endpoint() :: integer() | string().
7+
-type endpoint() :: string() | integer() .
88
-type verify() :: verify_peer | verify_none.
99

1010
-reflect_type([endpoint/0, verify/0]).
@@ -104,4 +104,3 @@ tr_listeners(Conf) ->
104104

105105
filter(Opts) ->
106106
[{K, V} || {K, V} <- Opts, V =/= undefined].
107-

sample-schemas/emqx_schema.erl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fields("node") ->
115115
, {"global_gc_interval", t(duration_s(), "emqx.global_gc_interval", undefined)}
116116
, {"fullsweep_after", t(non_neg_integer(),
117117
"vm_args.-env ERL_FULLSWEEP_AFTER", 1000)}
118-
, {"max_ets_tables", t(duration(), "vm_args.+e", 256000)}
118+
, {"max_ets_tables", t(integer(), "vm_args.+e", 256000)}
119119
, {"crash_dump", t(file(), "vm_args.-env ERL_CRASH_DUMP", undefined)}
120120
, {"dist_net_ticktime", t(integer(), "vm_args.-kernel net_ticktime", undefined)}
121121
, {"dist_listen_min", t(integer(), "kernel.inet_dist_listen_min", undefined)}
@@ -236,7 +236,7 @@ fields("zone") ->
236236
, {"upgrade_qos", t(flag(), undefined, false)}
237237
, {"max_inflight", t(range(0, 65535))}
238238
, {"retry_interval", t(duration_s(), undefined, "30s")}
239-
, {"max_awaiting_rel", t(duration(), undefined, 0)}
239+
, {"max_awaiting_rel", t(hoconsc:union([integer(), duration()]), undefined, 0)}
240240
, {"await_rel_timeout", t(duration_s(), undefined, "300s")}
241241
, {"ignore_loop_deliver", t(boolean())}
242242
, {"session_expiry_interval", t(duration_s(), undefined, "2h")}
@@ -379,24 +379,24 @@ fields("perf") ->
379379
];
380380

381381
fields("sysmon") ->
382-
[ {"long_gc", t(duration(), undefined, 0)}
383-
, {"long_schedule", t(duration(), undefined, 240)}
382+
[ {"long_gc", t(hoconsc:union([integer(), duration()]), undefined, 0)}
383+
, {"long_schedule", t(duration(), undefined, "240ms")}
384384
, {"large_heap", t(bytesize(), undefined, "8MB")}
385385
, {"busy_dist_port", t(boolean(), undefined, true)}
386386
, {"busy_port", t(boolean(), undefined, false)}
387387
];
388388

389389
fields("os_mon") ->
390-
[ {"cpu_check_interval", t(duration_s(), undefined, 60)}
390+
[ {"cpu_check_interval", t(duration_s(), undefined, "60s")}
391391
, {"cpu_high_watermark", t(percent(), undefined, "80%")}
392392
, {"cpu_low_watermark", t(percent(), undefined, "60%")}
393-
, {"mem_check_interval", t(duration_s(), undefined, 60)}
393+
, {"mem_check_interval", t(duration_s(), undefined, "60s")}
394394
, {"sysmem_high_watermark", t(percent(), undefined, "70%")}
395395
, {"procmem_high_watermark", t(percent(), undefined, "5%")}
396396
];
397397

398398
fields("vm_mon") ->
399-
[ {"check_interval", t(duration_s(), undefined, 30)}
399+
[ {"check_interval", t(duration_s(), undefined, "30s")}
400400
, {"process_high_watermark", t(percent(), undefined, "80%")}
401401
, {"process_low_watermark", t(percent(), undefined, "60%")}
402402
];

src/hocon_schema_builtin.erl

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,7 @@ convert(Symbol, ?ENUM(_OfSymbols)) ->
4343
Symbol
4444
end;
4545
convert(Int, Type) when is_integer(Int) ->
46-
case Type =:= string() of
47-
true ->
48-
integer_to_list(Int);
49-
false ->
50-
Int
51-
end;
46+
convert(integer_to_list(Int), Type);
5247
convert(Bin, Type) when is_binary(Bin) ->
5348
Str = unicode:characters_to_list(Bin, utf8),
5449
convert(Str, Type);

test/hocon_schema_builtin_tests.erl

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
%%--------------------------------------------------------------------
2+
%% Copyright (c) 2021-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(hocon_schema_builtin_tests).
17+
18+
-include_lib("typerefl/include/types.hrl").
19+
-include_lib("eunit/include/eunit.hrl").
20+
-include("hocon_private.hrl").
21+
-include("hoconsc.hrl").
22+
23+
-export([roots/0, fields/1, to_ip_port/1]).
24+
25+
-type ip_port() :: tuple() | integer().
26+
27+
-typerefl_from_string({ip_port/0, ?MODULE, to_ip_port}).
28+
-reflect_type([ip_port/0]).
29+
30+
roots() ->
31+
[listener].
32+
33+
fields(listener) ->
34+
[{"bind", hoconsc:mk(ip_port(), #{default => 80})}].
35+
36+
builtin_check_test() ->
37+
Conf = "listener.bind = 1024",
38+
?assertEqual(#{<<"listener">> => #{<<"bind">> => 1024}}, check_plain(Conf)),
39+
Conf1 = "listener.bind = 0",
40+
?assertEqual(#{<<"listener">> => #{<<"bind">> => 0}}, check_plain(Conf1)),
41+
Conf2 = "listener.bind = 65535",
42+
?assertEqual(#{<<"listener">> => #{<<"bind">> => 65535}}, check_plain(Conf2)),
43+
BadConf1 = "listener.bind = 65536",
44+
?assertThrow(
45+
#{
46+
exception := "port_number_too_large",
47+
field := <<"bind">>,
48+
path := "listener",
49+
reason := failed_to_check_field
50+
},
51+
check_plain(BadConf1)
52+
),
53+
BadConf2 = "listener.bind = -1",
54+
?assertThrow(
55+
#{
56+
exception := "port_number_must_be_positive",
57+
field := <<"bind">>,
58+
path := "listener",
59+
reason := failed_to_check_field
60+
},
61+
check_plain(BadConf2)
62+
),
63+
BadConf3 = "listener.bind = 1883d",
64+
?assertThrow(
65+
#{
66+
exception := "bad_port_number",
67+
field := <<"bind">>,
68+
path := "listener",
69+
reason := failed_to_check_field
70+
},
71+
check_plain(BadConf3)
72+
),
73+
ok.
74+
75+
check_plain(Str) ->
76+
{ok, Map} = hocon:binary(Str, #{}),
77+
hocon_tconf:check_plain(?MODULE, Map, #{}).
78+
79+
to_ip_port(Str) ->
80+
case split_ip_port(Str) of
81+
{"", Port} ->
82+
%% this is a local address
83+
{ok, parse_port(Port)};
84+
{MaybeIp, Port} ->
85+
PortVal = parse_port(Port),
86+
case inet:parse_address(MaybeIp) of
87+
{ok, IpTuple} ->
88+
{ok, {IpTuple, PortVal}};
89+
_ ->
90+
{error, bad_ip_port}
91+
end;
92+
_ ->
93+
{error, bad_ip_port}
94+
end.
95+
96+
split_ip_port(Str0) ->
97+
Str = re:replace(Str0, " ", "", [{return, list}, global]),
98+
case lists:split(string:rchr(Str, $:), Str) of
99+
%% no colon
100+
{[], Str} ->
101+
{"", Str};
102+
{IpPlusColon, PortString} ->
103+
IpStr0 = lists:droplast(IpPlusColon),
104+
case IpStr0 of
105+
%% drop head/tail brackets
106+
[$[ | S] ->
107+
case lists:last(S) of
108+
$] -> {lists:droplast(S), PortString};
109+
_ -> error
110+
end;
111+
_ ->
112+
{IpStr0, PortString}
113+
end
114+
end.
115+
116+
parse_port(Port) ->
117+
case string:to_integer(string:strip(Port)) of
118+
{P, ""} when P < 0 -> throw("port_number_must_be_positive");
119+
{P, ""} when P > 65535 -> throw("port_number_too_large");
120+
{P, ""} -> P;
121+
_ -> throw("bad_port_number")
122+
end.

0 commit comments

Comments
 (0)