diff --git a/apps/emqx/test/emqx_trace_SUITE.erl b/apps/emqx/test/emqx_trace_SUITE.erl index 555fc357e..3086dcdd7 100644 --- a/apps/emqx/test/emqx_trace_SUITE.erl +++ b/apps/emqx/test/emqx_trace_SUITE.erl @@ -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), diff --git a/apps/emqx/test/emqx_trace_handler_SUITE.erl b/apps/emqx/test/emqx_trace_handler_SUITE.erl index 6504530f1..e010b6c5e 100644 --- a/apps/emqx/test/emqx_trace_handler_SUITE.erl +++ b/apps/emqx/test/emqx_trace_handler_SUITE.erl @@ -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. diff --git a/apps/emqx_authn/src/emqx_authn_api.erl b/apps/emqx_authn/src/emqx_authn_api.erl index 9d632acfa..b83d9d1af 100644 --- a/apps/emqx_authn/src/emqx_authn_api.erl +++ b/apps/emqx_authn/src/emqx_authn_api.erl @@ -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( diff --git a/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl b/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl index b6724f701..59c0f560a 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl @@ -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) -> diff --git a/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl index c938788e4..3c70cfe65 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl @@ -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})}, diff --git a/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl index 149657ec0..ae74fc08e 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl @@ -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([ diff --git a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl index dff491225..4d4a9413e 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl @@ -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), diff --git a/bin/emqx b/bin/emqx index 63c09cc41..e1b72d1f9 100755 --- a/bin/emqx +++ b/bin/emqx @@ -587,6 +587,7 @@ case "${COMMAND}" in ping) assert_node_alive + echo pong ;; escript)