720 lines
25 KiB
Erlang
720 lines
25 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
|
%%
|
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
|
%% you may not use this file except in compliance with the License.
|
|
%% You may obtain a copy of the License at
|
|
%%
|
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
%%
|
|
%% Unless required by applicable law or agreed to in writing, software
|
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
%% See the License for the specific language governing permissions and
|
|
%% limitations under the License.
|
|
%%--------------------------------------------------------------------
|
|
|
|
-module(emqx_swagger_response_SUITE).
|
|
|
|
-behaviour(minirest_api).
|
|
-behaviour(hocon_schema).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
-include_lib("typerefl/include/types.hrl").
|
|
-include_lib("hocon/include/hoconsc.hrl").
|
|
-import(hoconsc, [mk/2]).
|
|
|
|
-compile(nowarn_export_all).
|
|
-compile(export_all).
|
|
|
|
-type url() :: emqx_http_lib:uri_map().
|
|
-reflect_type([url/0]).
|
|
-typerefl_from_string({url/0, emqx_http_lib, uri_parse}).
|
|
|
|
all() -> emqx_common_test_helpers:all(?MODULE).
|
|
|
|
init_per_suite(Config) ->
|
|
emqx_mgmt_api_test_util:init_suite([emqx_conf]),
|
|
Config.
|
|
|
|
end_per_suite(Config) ->
|
|
end_suite(),
|
|
Config.
|
|
|
|
end_suite() ->
|
|
application:unload(emqx_management),
|
|
emqx_mgmt_api_test_util:end_suite([emqx_conf]).
|
|
|
|
t_simple_binary(_config) ->
|
|
Path = "/simple/bin",
|
|
ExpectSpec = #{description => <<"binary ok">>},
|
|
ExpectRefs = [],
|
|
validate(Path, ExpectSpec, ExpectRefs),
|
|
ok.
|
|
|
|
t_object(_config) ->
|
|
Path = "/object",
|
|
Object =
|
|
#{
|
|
<<"content">> => #{
|
|
<<"application/json">> =>
|
|
#{
|
|
<<"schema">> => #{
|
|
required => [<<"per_page">>, <<"timeout">>],
|
|
<<"properties">> => [
|
|
{<<"per_page">>, #{
|
|
description => <<"good per page desc">>,
|
|
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),
|
|
ok.
|
|
|
|
t_error(_Config) ->
|
|
Path = "/error",
|
|
Error400 = #{
|
|
<<"content">> =>
|
|
#{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"type">> => object,
|
|
<<"properties">> =>
|
|
[
|
|
{<<"code">>, #{enum => ['Bad1', 'Bad2'], type => string}},
|
|
{<<"message">>, #{
|
|
description => <<"Bad request desc">>, type => string
|
|
}}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
Error404 = #{
|
|
<<"content">> =>
|
|
#{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"type">> => object,
|
|
<<"properties">> =>
|
|
[
|
|
{<<"code">>, #{enum => ['Not-Found'], type => string}},
|
|
{<<"message">>, #{
|
|
description => <<"Error code to troubleshoot problems.">>,
|
|
type => string
|
|
}}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{OperationId, Spec, Refs, #{}} = emqx_dashboard_swagger:parse_spec_ref(?MODULE, Path, #{}),
|
|
?assertEqual(test, OperationId),
|
|
Response = maps:get(responses, maps:get(get, Spec)),
|
|
?assertEqual(Error400, maps:get(<<"400">>, Response)),
|
|
?assertEqual(Error404, maps:get(<<"404">>, Response)),
|
|
?assertEqual(#{}, maps:without([<<"400">>, <<"404">>], Response)),
|
|
?assertEqual([], Refs),
|
|
ok.
|
|
|
|
t_nest_object(_Config) ->
|
|
Path = "/nest/object",
|
|
Object =
|
|
#{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> =>
|
|
#{
|
|
required => [<<"timeout">>],
|
|
<<"type">> => object,
|
|
<<"properties">> => [
|
|
{<<"per_page">>, #{
|
|
description => <<"good per page desc">>,
|
|
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">>, #{type => integer}},
|
|
{<<"good_nest_2">>, #{
|
|
<<"$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),
|
|
ok.
|
|
|
|
t_empty(_Config) ->
|
|
?assertThrow(
|
|
{error, #{
|
|
msg := <<"Object only supports not empty proplists">>,
|
|
args := [],
|
|
module := ?MODULE
|
|
}},
|
|
validate("/empty", error, [])
|
|
),
|
|
ok.
|
|
|
|
t_raw_local_ref(_Config) ->
|
|
Path = "/raw/ref/local",
|
|
Object = #{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{?MODULE, good_ref}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_raw_remote_ref(_Config) ->
|
|
Path = "/raw/ref/remote",
|
|
Object = #{
|
|
<<"content">> =>
|
|
#{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref1">>
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{emqx_swagger_remote_schema, "ref1"}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_local_ref(_Config) ->
|
|
Path = "/ref/local",
|
|
Object = #{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{?MODULE, good_ref}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_remote_ref(_Config) ->
|
|
Path = "/ref/remote",
|
|
Object = #{
|
|
<<"content">> =>
|
|
#{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.ref1">>
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{emqx_swagger_remote_schema, "ref1"}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_bad_ref(_Config) ->
|
|
Path = "/ref/bad",
|
|
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">>
|
|
}},
|
|
validate(Path, Object, ExpectRefs)
|
|
),
|
|
ok.
|
|
|
|
t_none_ref(_Config) ->
|
|
Path = "/ref/none",
|
|
?assertError(
|
|
{failed_to_generate_swagger_spec, ?MODULE, Path},
|
|
validate(Path, #{}, [])
|
|
),
|
|
ok.
|
|
|
|
t_nest_ref(_Config) ->
|
|
Path = "/ref/nest/ref",
|
|
Object = #{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.nest_ref">>
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{?MODULE, nest_ref}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_sub_fields(_Config) ->
|
|
Path = "/fields/sub",
|
|
Object = #{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
<<"$ref">> => <<"#/components/schemas/emqx_swagger_response_SUITE.sub_fields">>
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{?MODULE, sub_fields}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_complex_type(_Config) ->
|
|
Path = "/ref/complex_type",
|
|
{OperationId, Spec, Refs, #{}} = emqx_dashboard_swagger:parse_spec_ref(?MODULE, Path, #{}),
|
|
?assertEqual(test, OperationId),
|
|
Response = maps:get(responses, maps:get(post, Spec)),
|
|
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">>, #{
|
|
<<"oneOf">> := [
|
|
#{example := _, type := string},
|
|
#{enum := [infinity], type := string}
|
|
]
|
|
}},
|
|
{<<"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
|
|
}}
|
|
],
|
|
Properties
|
|
),
|
|
?assertEqual([], Refs),
|
|
ok.
|
|
|
|
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">>,
|
|
maximum => 100,
|
|
minimum => 1,
|
|
type => integer
|
|
}},
|
|
{<<"timeout">>, #{
|
|
default => 5,
|
|
<<"oneOf">> =>
|
|
[
|
|
#{example => <<"1h">>, type => string},
|
|
#{enum => [infinity], type => string}
|
|
]
|
|
}},
|
|
{<<"assert">>, #{description => <<"money">>, type => number}},
|
|
{<<"number_ex">>, #{description => <<"number example">>, type => number}},
|
|
{<<"percent_ex">>, #{
|
|
description => <<"percent example">>,
|
|
example => <<"12%">>,
|
|
type => string
|
|
}},
|
|
{<<"duration_ms_ex">>, #{
|
|
description => <<"duration ms example">>,
|
|
example => <<"32s">>,
|
|
type => string
|
|
}},
|
|
{<<"atom_ex">>, #{description => <<"atom ex">>, type => string}},
|
|
{<<"array_refs">>, #{
|
|
items => #{
|
|
<<"$ref">> =>
|
|
<<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>
|
|
},
|
|
type => array
|
|
}}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{?MODULE, good_ref}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
|
|
t_ref_array_without_key(_Config) ->
|
|
Path = "/ref/array/without/key",
|
|
Object = #{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> => #{
|
|
items => #{
|
|
<<"$ref">> =>
|
|
<<"#/components/schemas/emqx_swagger_response_SUITE.good_ref">>
|
|
},
|
|
type => array
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ExpectRefs = [{?MODULE, good_ref}],
|
|
validate(Path, Object, ExpectRefs),
|
|
ok.
|
|
t_hocon_schema_function(_Config) ->
|
|
Path = "/ref/hocon/schema/function",
|
|
Object = #{
|
|
<<"content">> => #{
|
|
<<"application/json">> => #{
|
|
<<"schema">> =>
|
|
#{<<"$ref">> => <<"#/components/schemas/emqx_swagger_remote_schema.root">>}
|
|
}
|
|
}
|
|
},
|
|
ExpectComponents = [
|
|
#{
|
|
<<"emqx_swagger_remote_schema.ref1">> => #{
|
|
<<"type">> => object,
|
|
<<"properties">> => [
|
|
{<<"protocol">>, #{enum => [http, https], type => string}},
|
|
{<<"port">>, #{default => 18083, type => integer}}
|
|
]
|
|
}
|
|
},
|
|
#{
|
|
<<"emqx_swagger_remote_schema.ref2">> => #{
|
|
<<"type">> => object,
|
|
<<"properties">> => [
|
|
{<<"page">>, #{
|
|
description => <<"good page">>,
|
|
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
|
|
}}
|
|
]
|
|
}
|
|
},
|
|
#{
|
|
<<"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
|
|
}},
|
|
{<<"default_username">>, #{default => <<"admin">>, type => string}},
|
|
{<<"default_password">>, #{default => <<"public">>, 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),
|
|
?assertEqual(ExpectComponents, Components),
|
|
ok.
|
|
|
|
t_api_spec(_Config) ->
|
|
emqx_dashboard_swagger:spec(?MODULE),
|
|
ok.
|
|
|
|
api_spec() -> emqx_dashboard_swagger:spec(?MODULE).
|
|
|
|
paths() ->
|
|
[
|
|
"/simple/bin",
|
|
"/object",
|
|
"/nest/object",
|
|
"/ref/local",
|
|
"/ref/nest/ref",
|
|
"/raw/ref/local",
|
|
"/raw/ref/remote",
|
|
"/ref/array/with/key",
|
|
"/ref/array/without/key",
|
|
"/ref/hocon/schema/function"
|
|
].
|
|
|
|
schema("/simple/bin") ->
|
|
to_schema(<<"binary ok">>);
|
|
schema("/object") ->
|
|
Object = [
|
|
{per_page, mk(range(1, 100), #{required => true, desc => <<"good per page desc">>})},
|
|
{timeout,
|
|
mk(
|
|
hoconsc:union([infinity, emqx_schema:timeout_duration_s()]),
|
|
#{default => 5, required => true}
|
|
)},
|
|
{inner_ref, mk(hoconsc:ref(?MODULE, good_ref), #{})}
|
|
],
|
|
to_schema(Object);
|
|
schema("/nest/object") ->
|
|
Response = [
|
|
{per_page, mk(range(1, 100), #{desc => <<"good per page desc">>})},
|
|
{timeout,
|
|
mk(
|
|
hoconsc:union([infinity, emqx_schema:timeout_duration_s()]),
|
|
#{default => 5, required => true}
|
|
)},
|
|
{nest_object, [
|
|
{good_nest_1, mk(integer(), #{})},
|
|
{good_nest_2, mk(hoconsc:ref(?MODULE, good_ref), #{})}
|
|
]},
|
|
{inner_ref, mk(hoconsc:ref(?MODULE, good_ref), #{})}
|
|
],
|
|
to_schema(Response);
|
|
schema("/empty") ->
|
|
to_schema([]);
|
|
schema("/raw/ref/local") ->
|
|
to_schema(hoconsc:ref(good_ref));
|
|
schema("/raw/ref/remote") ->
|
|
to_schema(hoconsc:ref(emqx_swagger_remote_schema, "ref1"));
|
|
schema("/ref/local") ->
|
|
to_schema(mk(hoconsc:ref(good_ref), #{}));
|
|
schema("/ref/remote") ->
|
|
to_schema(mk(hoconsc:ref(emqx_swagger_remote_schema, "ref1"), #{}));
|
|
schema("/ref/bad") ->
|
|
to_schema(mk(hoconsc:ref(?MODULE, bad_ref), #{}));
|
|
schema("/ref/nest/ref") ->
|
|
to_schema(mk(hoconsc:ref(?MODULE, nest_ref), #{}));
|
|
schema("/ref/array/with/key") ->
|
|
to_schema([
|
|
{per_page, mk(range(1, 100), #{desc => <<"good per page desc">>})},
|
|
{timeout,
|
|
mk(
|
|
hoconsc:union([infinity, emqx_schema:timeout_duration_s()]),
|
|
#{default => 5, required => true}
|
|
)},
|
|
{assert, mk(float(), #{desc => <<"money">>})},
|
|
{number_ex, mk(number(), #{desc => <<"number example">>})},
|
|
{percent_ex, mk(emqx_schema:percent(), #{desc => <<"percent example">>})},
|
|
{duration_ms_ex,
|
|
mk(emqx_schema:timeout_duration_ms(), #{desc => <<"duration ms example">>})},
|
|
{atom_ex, mk(atom(), #{desc => <<"atom ex">>})},
|
|
{array_refs, mk(hoconsc:array(hoconsc:ref(?MODULE, good_ref)), #{})}
|
|
]);
|
|
schema("/ref/array/without/key") ->
|
|
to_schema(mk(hoconsc:array(hoconsc:ref(?MODULE, good_ref)), #{}));
|
|
schema("/ref/hocon/schema/function") ->
|
|
to_schema(mk(hoconsc:ref(emqx_swagger_remote_schema, "root"), #{}));
|
|
schema("/error") ->
|
|
#{
|
|
operationId => test,
|
|
get => #{
|
|
responses => #{
|
|
400 => emqx_dashboard_swagger:error_codes(['Bad1', 'Bad2'], <<"Bad request desc">>),
|
|
404 => emqx_dashboard_swagger:error_codes(['Not-Found'])
|
|
}
|
|
}
|
|
};
|
|
schema("/ref/complex_type") ->
|
|
#{
|
|
operationId => test,
|
|
post => #{
|
|
responses => #{
|
|
200 => [
|
|
{no_neg_integer, hoconsc:mk(non_neg_integer(), #{})},
|
|
{url, hoconsc:mk(url(), #{})},
|
|
{server, hoconsc:mk(emqx_schema:ip_port(), #{})},
|
|
{connect_timeout, hoconsc:mk(emqx_schema:timeout_duration(), #{})},
|
|
{pool_type, hoconsc:mk(hoconsc:enum([random, hash]), #{})},
|
|
{timeout,
|
|
hoconsc:mk(hoconsc:union([infinity, emqx_schema:timeout_duration()]), #{})},
|
|
{bytesize, hoconsc:mk(emqx_schema:bytesize(), #{})},
|
|
{wordsize, hoconsc:mk(emqx_schema:wordsize(), #{})},
|
|
{maps, hoconsc:mk(map(), #{})},
|
|
{comma_separated_list, hoconsc:mk(emqx_schema:comma_separated_list(), #{})},
|
|
{comma_separated_atoms, hoconsc:mk(emqx_schema:comma_separated_atoms(), #{})},
|
|
{log_level, hoconsc:mk(emqx_conf_schema:log_level(), #{})}
|
|
]
|
|
}
|
|
}
|
|
};
|
|
schema("/fields/sub") ->
|
|
to_schema(hoconsc:ref(sub_fields)).
|
|
|
|
validate(Path, ExpectObject, ExpectRefs) ->
|
|
{OperationId, Spec, Refs, #{}} = emqx_dashboard_swagger:parse_spec_ref(?MODULE, Path, #{}),
|
|
?assertEqual(test, OperationId),
|
|
Response = maps:get(responses, maps:get(post, Spec)),
|
|
?assertEqual(ExpectObject, maps:get(<<"200">>, Response)),
|
|
?assertEqual(ExpectObject, maps:get(<<"201">>, Response)),
|
|
?assertEqual(#{}, maps:without([<<"201">>, <<"200">>], Response)),
|
|
?assertEqual(ExpectRefs, Refs),
|
|
{Spec, emqx_dashboard_swagger:components(Refs, #{})}.
|
|
|
|
to_schema(Object) ->
|
|
#{
|
|
operationId => test,
|
|
post => #{responses => #{200 => Object, 201 => Object}}
|
|
}.
|
|
|
|
namespace() -> undefined.
|
|
|
|
fields(good_ref) ->
|
|
[
|
|
{'webhook-host', mk(emqx_schema:ip_port(), #{default => <<"127.0.0.1:80">>})},
|
|
{log_dir, mk(string(), #{example => "var/log/emqx"})},
|
|
{tag, mk(binary(), #{desc => <<"tag">>})}
|
|
];
|
|
fields(nest_ref) ->
|
|
[
|
|
{env, mk(hoconsc:enum([test, dev, prod]), #{})},
|
|
{another_ref, mk(hoconsc:ref(good_ref), #{desc => "nest ref"})}
|
|
];
|
|
%% don't support maps
|
|
fields(bad_ref) ->
|
|
#{
|
|
username => mk(string(), #{}),
|
|
is_admin => mk(boolean(), #{})
|
|
};
|
|
fields(sub_fields) ->
|
|
#{
|
|
fields => [
|
|
{enable, fun enable/1},
|
|
{init_file, fun init_file/1}
|
|
],
|
|
desc => <<"test sub fields">>
|
|
}.
|
|
|
|
enable(type) -> boolean();
|
|
enable(desc) -> <<"Whether to enable tls psk support">>;
|
|
enable(default) -> false;
|
|
enable(_) -> undefined.
|
|
|
|
init_file(type) -> binary();
|
|
init_file(desc) -> <<"test test desc">>;
|
|
init_file(required) -> false;
|
|
init_file(_) -> undefined.
|