Fix ping not return pong (#6285)

* fix: ./bin/emqx ping return pong

* chore: waiting longer for logger flush log to disk

* fix: change swagger page's limit from 100 to 1000

* chore: type wrong

* fix: sync log to disk by logger_disk_log_h:filesync
This commit is contained in:
zhongwencool 2021-11-26 17:02:45 +08:00 committed by GitHub
parent 124ba7a071
commit f697028b70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 165 additions and 75 deletions

View File

@ -22,7 +22,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("emqx/include/emqx.hrl").
-import(emqx_trace_handler_SUITE, [filesync/2]).
-record(emqx_trace, {name, type, filter, enable = true, start_at, end_at}).
%%--------------------------------------------------------------------
@ -237,15 +237,16 @@ t_client_event(_Config) ->
emqtt:ping(Client),
ok = emqtt:publish(Client, <<"/test">>, #{}, <<"1">>, [{qos, 0}]),
ok = emqtt:publish(Client, <<"/test">>, #{}, <<"2">>, [{qos, 0}]),
ct:sleep(200),
ok = emqx_trace:create([{<<"name">>, <<"test_topic">>},
{<<"type">>, <<"topic">>}, {<<"topic">>, <<"/test">>}, {<<"start_at">>, Start}]),
ct:sleep(200),
ok = filesync(Name, clientid),
ok = filesync(<<"test_topic">>, topic),
{ok, Bin} = file:read_file(emqx_trace:log_file(Name, Now)),
ok = emqtt:publish(Client, <<"/test">>, #{}, <<"3">>, [{qos, 0}]),
ok = emqtt:publish(Client, <<"/test">>, #{}, <<"4">>, [{qos, 0}]),
ok = emqtt:disconnect(Client),
ct:sleep(200),
ok = filesync(Name, clientid),
ok = filesync(<<"test_topic">>, topic),
{ok, Bin2} = file:read_file(emqx_trace:log_file(Name, Now)),
{ok, Bin3} = file:read_file(emqx_trace:log_file(<<"test_topic">>, Now)),
ct:pal("Bin ~p Bin2 ~p Bin3 ~p", [byte_size(Bin), byte_size(Bin2), byte_size(Bin3)]),
@ -301,7 +302,7 @@ t_download_log(_Config) ->
{ok, Client} = emqtt:start_link([{clean_start, true}, {clientid, ClientId}]),
{ok, _} = emqtt:connect(Client),
[begin _ = emqtt:ping(Client) end ||_ <- lists:seq(1, 5)],
ct:sleep(100),
ok = filesync(Name, clientid),
{ok, ZipFile} = emqx_trace_api:download_zip_log(#{name => Name}, []),
?assert(filelib:file_size(ZipFile) > 0),
ok = emqtt:disconnect(Client),

View File

@ -62,7 +62,9 @@ t_trace_clientid(_Config) ->
emqx_trace_handler:install(clientid, <<"client4">>, bad_level, "tmp/client4.log"),
{error, {handler_not_added, {file_error, ".", eisdir}}} =
emqx_trace_handler:install(clientid, <<"client5">>, debug, "."),
ct:sleep(100),
ok = filesync(<<"client">>, clientid),
ok = filesync(<<"client2">>, clientid),
ok = filesync(<<"client3">>, clientid),
%% Verify the tracing file exits
?assert(filelib:is_regular("tmp/client.log")),
@ -83,7 +85,10 @@ t_trace_clientid(_Config) ->
emqtt:connect(T),
emqtt:publish(T, <<"a/b/c">>, <<"hi">>),
emqtt:ping(T),
ct:sleep(200),
ok = filesync(<<"client">>, clientid),
ok = filesync(<<"client2">>, clientid),
ok = filesync(<<"client3">>, clientid),
%% Verify messages are logged to "tmp/client.log" but not "tmp/client2.log".
{ok, Bin} = file:read_file("tmp/client.log"),
@ -109,7 +114,8 @@ t_trace_topic(_Config) ->
emqx_logger:set_log_level(debug),
ok = emqx_trace_handler:install(topic, <<"x/#">>, all, "tmp/topic_trace_x.log"),
ok = emqx_trace_handler:install(topic, <<"y/#">>, all, "tmp/topic_trace_y.log"),
ct:sleep(100),
ok = filesync(<<"x/#">>, topic),
ok = filesync(<<"y/#">>, topic),
%% Verify the tracing file exits
?assert(filelib:is_regular("tmp/topic_trace_x.log")),
@ -128,7 +134,8 @@ t_trace_topic(_Config) ->
emqtt:publish(T, <<"x/y/z">>, <<"hi2">>),
emqtt:subscribe(T, <<"x/y/z">>),
emqtt:unsubscribe(T, <<"x/y/z">>),
ct:sleep(200),
ok = filesync(<<"x/#">>, topic),
ok = filesync(<<"y/#">>, topic),
{ok, Bin} = file:read_file("tmp/topic_trace_x.log"),
?assertNotEqual(nomatch, binary:match(Bin, [<<"hi1">>])),
@ -152,8 +159,8 @@ t_trace_ip_address(_Config) ->
%% Start tracing
ok = emqx_trace_handler:install(ip_address, "127.0.0.1", all, "tmp/ip_trace_x.log"),
ok = emqx_trace_handler:install(ip_address, "192.168.1.1", all, "tmp/ip_trace_y.log"),
ct:sleep(100),
ok = filesync(<<"127.0.0.1">>, ip_address),
ok = filesync(<<"192.168.1.1">>, ip_address),
%% Verify the tracing file exits
?assert(filelib:is_regular("tmp/ip_trace_x.log")),
?assert(filelib:is_regular("tmp/ip_trace_y.log")),
@ -173,7 +180,8 @@ t_trace_ip_address(_Config) ->
emqtt:publish(T, <<"x/y/z">>, <<"hi2">>),
emqtt:subscribe(T, <<"x/y/z">>),
emqtt:unsubscribe(T, <<"x/y/z">>),
ct:sleep(200),
ok = filesync(<<"127.0.0.1">>, ip_address),
ok = filesync(<<"192.168.1.1">>, ip_address),
{ok, Bin} = file:read_file("tmp/ip_trace_x.log"),
?assertNotEqual(nomatch, binary:match(Bin, [<<"hi1">>])),
@ -189,3 +197,19 @@ t_trace_ip_address(_Config) ->
{error, _Reason} = emqx_trace_handler:uninstall(ip_address, <<"127.0.0.2">>),
emqtt:disconnect(T),
?assertEqual([], emqx_trace_handler:running()).
filesync(Name, Type) ->
filesync(Name, Type, 3).
%% sometime the handler process is not started yet.
filesync(_Name, _Type, 0) -> ok;
filesync(Name, Type, Retry) ->
try
Handler = binary_to_atom(<<"trace_",
(atom_to_binary(Type))/binary, "_", Name/binary>>),
ok = logger_disk_log_h:filesync(Handler)
catch E:R ->
ct:pal("Filesync error:~p ~p~n", [{Name, Type, Retry}, {E, R}]),
ct:sleep(100),
filesync(Name, Type, Retry - 1)
end.

View File

@ -21,6 +21,7 @@
-include_lib("typerefl/include/types.hrl").
-include("emqx_authn.hrl").
-include_lib("emqx/include/emqx_placeholder.hrl").
-include_lib("emqx/include/logger.hrl").
-import(hoconsc, [mk/2, ref/1]).
-import(emqx_dashboard_swagger, [error_codes/2]).
@ -590,7 +591,7 @@ listener_authenticator(delete,
authenticator_move(post,
#{bindings := #{id := AuthenticatorID},
body := #{<<"position">> := Position}}) ->
move_authenitcator([authentication], ?GLOBAL, AuthenticatorID, Position);
move_authenticator([authentication], ?GLOBAL, AuthenticatorID, Position);
authenticator_move(post, #{bindings := #{id := _}, body := _}) ->
serialize_error({missing_parameter, position}).
@ -599,7 +600,7 @@ listener_authenticator_move(post,
body := #{<<"position">> := Position}}) ->
with_listener(ListenerID,
fun(Type, Name, ChainName) ->
move_authenitcator([listeners, Type, Name, authentication],
move_authenticator([listeners, Type, Name, authentication],
ChainName,
AuthenticatorID,
Position)
@ -771,7 +772,7 @@ delete_authenticator(ConfKeyPath, ChainName, AuthenticatorID) ->
serialize_error(Reason)
end.
move_authenitcator(ConfKeyPath, ChainName, AuthenticatorID, Position) ->
move_authenticator(ConfKeyPath, ChainName, AuthenticatorID, Position) ->
case parse_position(Position) of
{ok, NPosition} ->
case update_config(

View File

@ -31,7 +31,8 @@
-define(TO_COMPONENTS_PARAM(_M_, _F_), iolist_to_binary([<<"#/components/parameters/">>,
?TO_REF(namespace(_M_), _F_)])).
-define(MAX_ROW_LIMIT, 100).
-define(MAX_ROW_LIMIT, 1000).
-define(DEFAULT_ROW, 100).
-type(request() :: #{bindings => map(), query_string => map(), body => map()}).
-type(request_meta() :: #{module => module(), path => string(), method => atom()}).
@ -80,7 +81,7 @@ fields(page) ->
fields(limit) ->
Desc = iolist_to_binary([<<"Results per page(max ">>,
integer_to_binary(?MAX_ROW_LIMIT), <<")">>]),
Meta = #{in => query, desc => Desc, default => ?MAX_ROW_LIMIT, example => 50},
Meta = #{in => query, desc => Desc, default => ?DEFAULT_ROW, example => 50},
[{limit, hoconsc:mk(range(1, ?MAX_ROW_LIMIT), Meta)}].
-spec(schema_with_example(hocon_schema:type(), term()) -> hocon_schema:field_schema_map()).
@ -123,10 +124,10 @@ translate_req(Request, #{module := Module, path := Path, method := Method}, Chec
{Bindings, QueryStr} = check_parameters(Request, Params, Module),
NewBody = check_request_body(Request, Body, Module, CheckFun, hoconsc:is_schema(Body)),
{ok, Request#{bindings => Bindings, query_string => QueryStr, body => NewBody}}
catch throw:Error ->
{_, [{validation_error, ValidErr}]} = Error,
#{path := Key, reason := Reason} = ValidErr,
{400, 'BAD_REQUEST', iolist_to_binary(io_lib:format("~ts : ~p", [Key, Reason]))}
catch throw:{_, ValidErrors} ->
Msg = [io_lib:format("~ts : ~p", [Key, Reason]) ||
{validation_error, #{path := Key, reason := Reason}} <- ValidErrors],
{400, 'BAD_REQUEST', iolist_to_binary(string:join(Msg, ","))}
end.
check_and_translate(Schema, Map, Opts) ->

View File

@ -71,8 +71,10 @@ t_public_ref(_Config) ->
{emqx_dashboard_swagger, page, parameter}
], Refs),
ExpectRefs = [
#{<<"public.limit">> => #{description => <<"Results per page(max 100)">>, example => 50,in => query,name => limit,
schema => #{default => 100,example => 1,maximum => 100, minimum => 1,type => integer}}},
#{<<"public.limit">> => #{description => <<"Results per page(max 1000)">>,
example => 50,in => query,name => limit,
schema => #{default => 100,example => 1,maximum => 1000,
minimum => 1,type => integer}}},
#{<<"public.page">> => #{description => <<"Page number of the results to fetch.">>,
example => 1,in => query,name => page,
schema => #{default => 1,example => 100,type => integer}}}],
@ -176,7 +178,8 @@ t_in_mix_trans(_Config) ->
Expect = {ok,
#{body => #{},
bindings => #{state => 720},
query_string => #{<<"filter">> => created,<<"is_admin">> => true, <<"per_page">> => 5,<<"timeout">> => 34}}},
query_string => #{<<"filter">> => created,<<"is_admin">> => true,
<<"per_page">> => 5,<<"timeout">> => 34}}},
?assertEqual(Expect, trans_parameters(Path, Bindings, Query)),
ok.
@ -268,7 +271,10 @@ schema("/test/in/:filter") ->
parameters => [
{filter,
mk(hoconsc:enum([assigned, created, mentioned, all]),
#{in => path, desc => <<"Indicates which sorts of issues to return">>, example => "all"})}
#{in => path,
desc => <<"Indicates which sorts of issues to return">>,
example => "all"
})}
],
responses => #{200 => <<"ok">>}
}
@ -323,9 +329,11 @@ schema("/test/in/mix/:state") ->
deprecated => true,
parameters => [
{filter, hoconsc:mk(hoconsc:enum([assigned, created, mentioned, all]),
#{in => query, desc => <<"Indicates which sorts of issues to return">>, example => "all"})},
#{in => query, desc => <<"Indicates which sorts of issues to return">>,
example => "all"})},
{state, mk(emqx_schema:duration_s(),
#{in => path, required => true, example => "12m", desc => <<"Indicates the state of the issues to return.">>})},
#{in => path, required => true, example => "12m",
desc => <<"Indicates the state of the issues to return.">>})},
{per_page, mk(range(1, 50),
#{in => query, required => false, example => 10, default => 5})},
{is_admin, mk(boolean(), #{in => query})},

View File

@ -47,9 +47,14 @@ t_object(_Config) ->
#{<<"schema">> =>
#{required => [<<"timeout">>, <<"per_page">>],
<<"properties">> =>[
{<<"per_page">>, #{description => <<"good per page desc">>, example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> => [#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
{<<"inner_ref">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
{<<"per_page">>, #{description => <<"good per page desc">>,
example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> =>
[#{example => <<"1h">>, type => string},
#{enum => [infinity], type => string}]}},
{<<"inner_ref">>,
#{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
<<"type">> => object}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{?MODULE, good_ref}],
@ -63,14 +68,20 @@ t_nest_object(_Config) ->
#{<<"schema">> =>
#{required => [<<"timeout">>],
<<"properties">> =>
[{<<"per_page">>, #{description => <<"good per page desc">>, example => 1, maximum => 100, minimum => 1, type => integer}},
[{<<"per_page">>, #{description => <<"good per page desc">>,
example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> =>
[#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
[#{example => <<"1h">>, type => string},
#{enum => [infinity], type => string}]}},
{<<"nest_object">>,
#{<<"properties">> =>
[{<<"good_nest_1">>, #{example => 100, type => integer}},
{<<"good_nest_2">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],<<"type">> => object}},
{<<"inner_ref">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
{<<"good_nest_2">>, #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
<<"type">> => object}},
{<<"inner_ref">>,
#{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
<<"type">> => object}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{?MODULE, good_ref}],
@ -81,7 +92,8 @@ t_local_ref(_Config) ->
Spec = #{
post => #{parameters => [],
requestBody => #{<<"content">> => #{<<"application/json">> =>
#{<<"schema">> => #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}}},
#{<<"schema">> => #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{?MODULE, good_ref}],
validate("/ref/local", Spec, Refs),
@ -91,17 +103,22 @@ t_remote_ref(_Config) ->
Spec = #{
post => #{parameters => [],
requestBody => #{<<"content">> => #{<<"application/json">> =>
#{<<"schema">> => #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref2">>}}}},
#{<<"schema">> => #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_remote_schema.ref2">>}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{emqx_swagger_remote_schema, "ref2"}],
{_, Components} = validate("/ref/remote", Spec, Refs),
ExpectComponents = [
#{<<"emqx_swagger_remote_schema.ref2">> => #{<<"properties">> => [
{<<"page">>, #{description => <<"good page">>,example => 1, maximum => 100,minimum => 1,type => integer}},
{<<"another_ref">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref3">>}}], <<"type">> => object}},
{<<"page">>, #{description => <<"good page">>,example => 1,
maximum => 100,minimum => 1,type => integer}},
{<<"another_ref">>, #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_remote_schema.ref3">>}}], <<"type">> => object}},
#{<<"emqx_swagger_remote_schema.ref3">> => #{<<"properties">> => [
{<<"ip">>, #{description => <<"IP:Port">>, example => <<"127.0.0.1:80">>,type => string}},
{<<"version">>, #{description => <<"a good version">>, example => <<"1.0.0">>,type => string}}],
{<<"ip">>, #{description => <<"IP:Port">>,
example => <<"127.0.0.1:80">>,type => string}},
{<<"version">>, #{description => <<"a good version">>,
example => <<"1.0.0">>,type => string}}],
<<"type">> => object}}],
?assertEqual(ExpectComponents, Components),
ok.
@ -110,18 +127,22 @@ t_nest_ref(_Config) ->
Spec = #{
post => #{parameters => [],
requestBody => #{<<"content">> => #{<<"application/json">> =>
#{<<"schema">> => #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.nest_ref">>}}}},
#{<<"schema">> => #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.nest_ref">>}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{?MODULE, nest_ref}],
ExpectComponents = lists:sort([
#{<<"emqx_swagger_requestBody_SUITE.nest_ref">> => #{<<"properties">> => [
{<<"env">>, #{enum => [test,dev,prod],type => string}},
{<<"another_ref">>, #{description => <<"nest ref">>, <<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
{<<"another_ref">>, #{description => <<"nest ref">>,
<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}}],
<<"type">> => object}},
#{<<"emqx_swagger_requestBody_SUITE.good_ref">> => #{<<"properties">> => [
{<<"webhook-host">>, #{default => <<"127.0.0.1:80">>, example => <<"127.0.0.1:80">>,type => string}},
{<<"webhook-host">>, #{default => <<"127.0.0.1:80">>,
example => <<"127.0.0.1:80">>,type => string}},
{<<"log_dir">>, #{example => <<"var/log/emqx">>,type => string}},
{<<"tag">>, #{description => <<"tag">>, example => <<"binary-example">>,type => string}}],
{<<"tag">>, #{description => <<"tag">>,
example => <<"binary-example">>,type => string}}],
<<"type">> => object}}]),
{_, Components} = validate("/ref/nest/ref", Spec, Refs),
?assertEqual(ExpectComponents, Components),
@ -153,9 +174,14 @@ t_ref_array_with_key(_Config) ->
#{<<"schema">> => #{required => [<<"timeout">>],
<<"type">> => object, <<"properties">> =>
[
{<<"per_page">>, #{description => <<"good per page desc">>, example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> => [#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
{<<"array_refs">>, #{items => #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}, type => array}}
{<<"per_page">>, #{description => <<"good per page desc">>,
example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> =>
[#{example => <<"1h">>, type => string},
#{enum => [infinity], type => string}]}},
{<<"array_refs">>, #{items => #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>},
type => array}}
]}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{?MODULE, good_ref}],
@ -166,7 +192,8 @@ t_ref_array_without_key(_Config) ->
Spec = #{
post => #{parameters => [],
requestBody => #{<<"content">> => #{<<"application/json">> => #{<<"schema">> =>
#{items => #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}, type => array}}}},
#{items => #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_requestBody_SUITE.good_ref">>}, type => array}}}},
responses => #{<<"200">> => #{description => <<"ok">>}}}},
Refs = [{?MODULE, good_ref}],
validate("/ref/array/without/key", Spec, Refs),
@ -190,7 +217,8 @@ t_api_spec(_Config) ->
{ok, #{body := #{<<"timeout">> := <<"infinity">>}}},
trans_requestBody(Path, Body, Filter0)),
{Spec1, _} = emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}),
{Spec1, _} = emqx_dashboard_swagger:spec(?MODULE,
#{check_schema => true, translate_body => true}),
Filter1 = filter(Spec1, Path),
?assertMatch(
{ok, #{body := #{<<"timeout">> := infinity}}},
@ -237,7 +265,8 @@ t_object_notrans(_Config) ->
<<"tag">> => <<"god_tag">>
}
},
{ok, #{body := ActualBody}} = trans_requestBody(Path, Body, fun emqx_dashboard_swagger:filter_check_request/2),
{ok, #{body := ActualBody}} = trans_requestBody(Path, Body,
fun emqx_dashboard_swagger:filter_check_request/2),
?assertEqual(Body, ActualBody),
ok.
@ -444,7 +473,8 @@ filter(ApiSpec, Path) ->
Filter.
trans_requestBody(Path, Body) ->
trans_requestBody(Path, Body, fun emqx_dashboard_swagger:filter_check_request_and_translate_body/2).
trans_requestBody(Path, Body,
fun emqx_dashboard_swagger:filter_check_request_and_translate_body/2).
trans_requestBody(Path, Body, Filter) ->
Meta = #{module => ?MODULE, method => post, path => Path},
@ -453,7 +483,8 @@ trans_requestBody(Path, Body, Filter) ->
api_spec() -> emqx_dashboard_swagger:spec(?MODULE).
paths() ->
["/object", "/nest/object", "/ref/local", "/ref/nest/ref", "/ref/array/with/key", "/ref/array/without/key"].
["/object", "/nest/object", "/ref/local", "/ref/nest/ref",
"/ref/array/with/key", "/ref/array/without/key"].
schema("/object") ->
to_schema([

View File

@ -40,9 +40,12 @@ t_object(_config) ->
#{<<"content">> => #{<<"application/json">> =>
#{<<"schema">> => #{required => [<<"timeout">>, <<"per_page">>],
<<"properties">> => [
{<<"per_page">>, #{description => <<"good per page desc">>, example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> => [#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
{<<"inner_ref">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}}],
{<<"per_page">>, #{description => <<"good per page desc">>,
example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> =>
[#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
{<<"inner_ref">>, #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}}],
<<"type">> => object}}}},
ExpectRefs = [{?MODULE, good_ref}],
validate(Path, Object, ExpectRefs),
@ -80,14 +83,17 @@ t_nest_object(_Config) ->
Object =
#{<<"content">> => #{<<"application/json">> => #{<<"schema">> =>
#{required => [<<"timeout">>], <<"type">> => object, <<"properties">> => [
{<<"per_page">>, #{description => <<"good per page desc">>, example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"per_page">>, #{description => <<"good per page desc">>, example => 1,
maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> =>
[#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
{<<"nest_object">>, #{<<"type">> => object, <<"properties">> => [
{<<"good_nest_1">>, #{example => 100, type => integer}},
{<<"good_nest_2">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}
{<<"good_nest_2">>, #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}
}]}},
{<<"inner_ref">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}}]
{<<"inner_ref">>, #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}}]
}}}},
ExpectRefs = [{?MODULE, good_ref}],
validate(Path, Object, ExpectRefs),
@ -138,7 +144,8 @@ t_bad_ref(_Config) ->
Object = #{<<"content">> => #{<<"application/json">> => #{<<"schema">> =>
#{<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.bad_ref">>}}}},
ExpectRefs = [{?MODULE, bad_ref}],
?assertThrow({error, #{module := ?MODULE, msg := <<"Object only supports not empty proplists">>}},
?assertThrow({error, #{module := ?MODULE,
msg := <<"Object only supports not empty proplists">>}},
validate(Path, Object, ExpectRefs)),
ok.
@ -158,7 +165,8 @@ t_nest_ref(_Config) ->
t_complicated_type(_Config) ->
Path = "/ref/complicated_type",
Object = #{<<"content">> => #{<<"application/json">> => #{<<"schema">> => #{<<"properties">> =>
Object = #{<<"content">> => #{<<"application/json">> =>
#{<<"schema">> => #{<<"properties">> =>
[
{<<"no_neg_integer">>, #{example => 100, minimum => 1, type => integer}},
{<<"url">>, #{example => <<"http://127.0.0.1">>, type => string}},
@ -176,7 +184,8 @@ t_complicated_type(_Config) ->
{<<"comma_separated_list">>, #{example => <<"item1,item2">>, type => string}},
{<<"comma_separated_atoms">>, #{example => <<"item1,item2">>, type => string}},
{<<"log_level">>,
#{enum => [debug, info, notice, warning, error, critical, alert, emergency, all], type => string}},
#{enum => [debug, info, notice, warning, error, critical, alert, emergency, all],
type => string}},
{<<"fix_integer">>, #{default => 100, enum => [100], example => 100,type => integer}}
],
<<"type">> => object}}}},
@ -192,15 +201,20 @@ t_ref_array_with_key(_Config) ->
Path = "/ref/array/with/key",
Object = #{<<"content">> => #{<<"application/json">> => #{<<"schema">> => #{
required => [<<"timeout">>], <<"type">> => object, <<"properties">> => [
{<<"per_page">>, #{description => <<"good per page desc">>, example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"per_page">>, #{description => <<"good per page desc">>,
example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"timeout">>, #{default => 5, <<"oneOf">> =>
[#{example => <<"1h">>, type => string}, #{enum => [infinity], type => string}]}},
{<<"assert">>, #{description => <<"money">>, example => 3.14159, type => number}},
{<<"number_ex">>, #{description => <<"number example">>, example => 42, type => number}},
{<<"percent_ex">>, #{description => <<"percent example">>, example => <<"12%">>, type => number}},
{<<"duration_ms_ex">>, #{description => <<"duration ms example">>, example => <<"32s">>, type => string}},
{<<"number_ex">>, #{description => <<"number example">>,
example => 42, type => number}},
{<<"percent_ex">>, #{description => <<"percent example">>,
example => <<"12%">>, type => number}},
{<<"duration_ms_ex">>, #{description => <<"duration ms example">>,
example => <<"32s">>, type => string}},
{<<"atom_ex">>, #{description => <<"atom ex">>, example => atom, type => string}},
{<<"array_refs">>, #{items => #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}, type => array}}
{<<"array_refs">>, #{items => #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>}, type => array}}
]}
}}},
ExpectRefs = [{?MODULE, good_ref}],
@ -227,25 +241,34 @@ t_hocon_schema_function(_Config) ->
}},
#{<<"emqx_swagger_remote_schema.ref2">> => #{<<"type">> => object,
<<"properties">> => [
{<<"page">>, #{description => <<"good page">>, example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"another_ref">>, #{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref3">>}}
{<<"page">>, #{description => <<"good page">>,
example => 1, maximum => 100, minimum => 1, type => integer}},
{<<"another_ref">>, #{<<"$ref">> =>
<<"#/components/schemas/emqx_swagger_remote_schema.ref3">>}}
]
}},
#{<<"emqx_swagger_remote_schema.ref3">> => #{<<"type">> => object,
<<"properties">> => [
{<<"ip">>, #{description => <<"IP:Port">>, example => <<"127.0.0.1:80">>, type => string}},
{<<"version">>, #{description => <<"a good version">>, example => <<"1.0.0">>, type => string}}]
{<<"ip">>, #{description => <<"IP:Port">>,
example => <<"127.0.0.1:80">>, type => string}},
{<<"version">>, #{description => <<"a good version">>,
example => <<"1.0.0">>, type => string}}]
}},
#{<<"emqx_swagger_remote_schema.root">> => #{required => [<<"default_password">>, <<"default_username">>],
#{<<"emqx_swagger_remote_schema.root">> =>
#{required => [<<"default_password">>, <<"default_username">>],
<<"properties">> => [{<<"listeners">>, #{items =>
#{<<"oneOf">> =>
[#{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref2">>},
#{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref1">>}]}, type => array}},
#{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref1">>}]},
type => array}},
{<<"default_username">>,
#{default => <<"admin">>, example => <<"string-example">>, type => string}},
{<<"default_password">>, #{default => <<"public">>, example => <<"string-example">>, type => string}},
{<<"sample_interval">>, #{default => <<"10s">>, example => <<"1h">>, type => string}},
{<<"token_expired_time">>, #{default => <<"30m">>, example => <<"12m">>, type => string}}],
{<<"default_password">>,
#{default => <<"public">>, example => <<"string-example">>, type => string}},
{<<"sample_interval">>,
#{default => <<"10s">>, example => <<"1h">>, type => string}},
{<<"token_expired_time">>,
#{default => <<"30m">>, example => <<"12m">>, type => string}}],
<<"type">> => object}}],
ExpectRefs = [{emqx_swagger_remote_schema, "root"}],
{_, Components} = validate(Path, Object, ExpectRefs),

View File

@ -587,6 +587,7 @@ case "${COMMAND}" in
ping)
assert_node_alive
echo pong
;;
escript)