diff --git a/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl b/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl index 4a8072804..4a316e248 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_swagger.erl @@ -345,15 +345,7 @@ parse_spec_ref(Module, Path, Options) -> erlang:apply(Module, schema, [Path]) catch Error:Reason:Stacktrace -> - %% This error is intended to fail the build - %% hence print to standard_error - io:format( - standard_error, - "Failed to generate swagger for path ~p in module ~p~n" - "error:~p~nreason:~p~n~p~n", - [Module, Path, Error, Reason, Stacktrace] - ), - error({failed_to_generate_swagger_spec, Module, Path}) + failed_to_generate_swagger_spec(Module, Path, Error, Reason, Stacktrace) end, OperationId = maps:get('operationId', Schema), {Specs, Refs} = maps:fold( @@ -369,6 +361,24 @@ parse_spec_ref(Module, Path, Options) -> RouteOpts = generate_route_opts(Schema, Options), {OperationId, Specs, Refs, RouteOpts}. +-ifdef(TEST). +-spec failed_to_generate_swagger_spec(_, _, _, _, _) -> no_return(). +failed_to_generate_swagger_spec(Module, Path, _Error, _Reason, _Stacktrace) -> + error({failed_to_generate_swagger_spec, Module, Path}). +-else. +-spec failed_to_generate_swagger_spec(_, _, _, _, _) -> no_return(). +failed_to_generate_swagger_spec(Module, Path, Error, Reason, Stacktrace) -> + %% This error is intended to fail the build + %% hence print to standard_error + io:format( + standard_error, + "Failed to generate swagger for path ~p in module ~p~n" + "error:~p~nreason:~p~n~p~n", + [Module, Path, Error, Reason, Stacktrace] + ), + error({failed_to_generate_swagger_spec, Module, Path}). + +-endif. generate_route_opts(Schema, Options) -> #{filter => compose_filters(filter(Options), custom_filter(Schema))}. diff --git a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl index d84f17c44..376ace5c2 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl @@ -317,68 +317,72 @@ t_sub_fields(_Config) -> validate(Path, Object, ExpectRefs), ok. -t_complicated_type(_Config) -> +t_complex_type(_Config) -> Path = "/ref/complex_type", - Object = #{ - <<"content">> => #{ - <<"application/json">> => - #{ - <<"schema">> => #{ - <<"properties">> => - [ - {<<"no_neg_integer">>, #{minimum => 0, type => integer}}, - {<<"url">>, #{example => <<"http://127.0.0.1">>, type => string}}, - {<<"server">>, #{example => <<"127.0.0.1:80">>, type => string}}, - {<<"connect_timeout">>, #{ - example => infinity, - <<"oneOf">> => [ - #{example => infinity, type => string}, - #{type => integer} - ] - }}, - {<<"pool_type">>, #{enum => [random, hash], type => string}}, - {<<"timeout">>, #{ - example => infinity, - <<"oneOf">> => [ - #{example => infinity, type => string}, #{type => integer} - ] - }}, - {<<"bytesize">>, #{example => <<"32MB">>, type => string}}, - {<<"wordsize">>, #{example => <<"1024KB">>, type => string}}, - {<<"maps">>, #{example => #{}, type => object}}, - {<<"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 - }}, - {<<"fix_integer">>, #{ - default => 100, enum => [100], type => integer - }} - ], - <<"type">> => object - } - } - } - }, {OperationId, Spec, Refs, #{}} = emqx_dashboard_swagger:parse_spec_ref(?MODULE, Path, #{}), ?assertEqual(test, OperationId), Response = maps:get(responses, maps:get(post, Spec)), - ?assertEqual(Object, maps:get(<<"200">>, Response)), + ResponseBody = maps:get(<<"200">>, Response), + Content = maps:get(<<"content">>, ResponseBody), + JsonContent = maps:get(<<"application/json">>, Content), + Schema = maps:get(<<"schema">>, JsonContent), + ?assertMatch(#{<<"type">> := object}, Schema), + Properties = maps:get(<<"properties">>, Schema), + ?assertMatch( + [ + {<<"no_neg_integer">>, #{minimum := 0, type := integer}}, + {<<"url">>, #{ + example := <<"http://127.0.0.1">>, type := string + }}, + {<<"server">>, #{ + example := <<"127.0.0.1:80">>, type := string + }}, + {<<"connect_timeout">>, #{ + example := _, type := string + }}, + {<<"pool_type">>, #{ + enum := [random, hash], type := string + }}, + {<<"timeout">>, #{ + example := infinity, + <<"oneOf">> := [ + #{example := infinity, type := string}, + #{type := integer} + ] + }}, + {<<"bytesize">>, #{ + example := <<"32MB">>, type := string + }}, + {<<"wordsize">>, #{ + example := <<"1024KB">>, type := string + }}, + {<<"maps">>, #{example := #{}, type := object}}, + {<<"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 + }}, + {<<"fix_integer">>, #{ + default := 100, enum := [100], type := integer + }} + ], + Properties + ), ?assertEqual([], Refs), ok. @@ -647,9 +651,8 @@ schema("/ref/complex_type") -> {no_neg_integer, hoconsc:mk(non_neg_integer(), #{})}, {url, hoconsc:mk(url(), #{})}, {server, hoconsc:mk(emqx_schema:ip_port(), #{})}, - {connect_timeout, - hoconsc:mk(emqx_bridge_http_connector:connect_timeout(), #{})}, - {pool_type, hoconsc:mk(emqx_bridge_http_connector:pool_type(), #{})}, + {connect_timeout, hoconsc:mk(emqx_schema:timeout_duration(), #{})}, + {pool_type, hoconsc:mk(hoconsc:enum([random, hash]), #{})}, {timeout, hoconsc:mk(timeout(), #{})}, {bytesize, hoconsc:mk(emqx_schema:bytesize(), #{})}, {wordsize, hoconsc:mk(emqx_schema:wordsize(), #{})},