refactor: only PUT, no POST for '/gateways'

This commit is contained in:
Stefan Strigler 2022-11-11 15:16:13 +01:00
parent 2914523117
commit 9cc5920b0d
8 changed files with 270 additions and 194 deletions

View File

@ -57,6 +57,14 @@ It's enum with `stomp`, `mqttsn`, `coap`, `lwm2m`, `exproto`
}
}
gateway_enable_in_path {
desc {
en: """Whether or not gateway is enabled"""
zh: """是否开启此网关"""
}
}
gateway_status {
desc {
en: """Gateway status"""

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*-
{application, emqx_gateway, [
{description, "The Gateway management application"},
{vsn, "0.1.7"},
{vsn, "0.1.8"},
{registered, []},
{mod, {emqx_gateway_app, []}},
{applications, [kernel, stdlib, grpc, emqx, emqx_authn]},

View File

@ -19,8 +19,6 @@
-include("emqx_gateway_http.hrl").
-include_lib("typerefl/include/types.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-include_lib("emqx/include/emqx_placeholder.hrl").
-include_lib("emqx/include/emqx_authentication.hrl").
-behaviour(minirest_api).
@ -49,8 +47,9 @@
%% http handlers
-export([
gateways/2,
gateway/2,
gateway_insta/2
gateway_enable/2
]).
-define(KNOWN_GATEWAY_STATUSES, [<<"running">>, <<"stopped">>, <<"unloaded">>]).
@ -66,13 +65,14 @@ api_spec() ->
paths() ->
emqx_gateway_utils:make_deprecated_paths([
"/gateways",
"/gateways/:name"
"/gateways/:name",
"/gateways/:name/enable/:enable"
]).
%%--------------------------------------------------------------------
%% http handlers
gateway(get, Request) ->
gateways(get, Request) ->
Params = maps:get(query_string, Request, #{}),
Status = maps:get(<<"status">>, Params, <<"all">>),
case lists:member(Status, [<<"all">> | ?KNOWN_GATEWAY_STATUSES]) of
@ -89,84 +89,85 @@ gateway(get, Request) ->
lists:join(", ", ?KNOWN_GATEWAY_STATUSES)
]
)
end;
gateway(post, Request) ->
Body = maps:get(body, Request, #{}),
try
Name0 = maps:get(<<"name">>, Body),
GwName = binary_to_existing_atom(Name0),
case emqx_gateway_registry:lookup(GwName) of
undefined ->
error(badarg);
_ ->
GwConf = maps:without([<<"name">>], Body),
case emqx_gateway_conf:load_gateway(GwName, GwConf) of
{ok, NGwConf} ->
{201, NGwConf};
{error, Reason} ->
emqx_gateway_http:reason2resp(Reason)
end
end
catch
error:{badkey, K} ->
return_http_error(400, [K, " is required"]);
error:{badconf, _} = Reason1 ->
emqx_gateway_http:reason2resp(Reason1);
error:badarg ->
return_http_error(404, "Bad gateway name")
end.
gateway_insta(delete, #{bindings := #{name := Name0}}) ->
with_gateway(Name0, fun(GwName, _) ->
case emqx_gateway_conf:unload_gateway(GwName) of
ok ->
gateway(get, #{bindings := #{name := Name}}) ->
try
GwName = gw_name(Name),
case emqx_gateway:lookup(GwName) of
undefined ->
{200, #{name => GwName, status => unloaded}};
Gateway ->
GwConf = emqx_gateway_conf:gateway(Name),
GwInfo0 = emqx_gateway_utils:unix_ts_to_rfc3339(
[created_at, started_at, stopped_at],
Gateway
),
GwInfo1 = maps:with(
[
name,
status,
created_at,
started_at,
stopped_at
],
GwInfo0
),
{200, maps:merge(GwConf, GwInfo1)}
end
catch
throw:not_found ->
return_http_error(404, <<"NOT FOUND">>)
end;
gateway(put, #{
body := GwConf0,
bindings := #{name := Name}
}) ->
GwConf = maps:without([<<"name">>], GwConf0),
try
GwName = gw_name(Name),
LoadOrUpdateF =
case emqx_gateway:lookup(GwName) of
undefined ->
fun emqx_gateway_conf:load_gateway/2;
_ ->
fun emqx_gateway_conf:update_gateway/2
end,
case LoadOrUpdateF(GwName, GwConf) of
{ok, _} ->
{204};
{error, Reason} ->
emqx_gateway_http:reason2resp(Reason)
end
end);
gateway_insta(get, #{bindings := #{name := Name0}}) ->
try binary_to_existing_atom(Name0) of
GwName ->
case emqx_gateway:lookup(GwName) of
undefined ->
{200, #{name => GwName, status => unloaded}};
Gateway ->
GwConf = emqx_gateway_conf:gateway(Name0),
GwInfo0 = emqx_gateway_utils:unix_ts_to_rfc3339(
[created_at, started_at, stopped_at],
Gateway
),
GwInfo1 = maps:with(
[
name,
status,
created_at,
started_at,
stopped_at
],
GwInfo0
),
{200, maps:merge(GwConf, GwInfo1)}
end
catch
error:badarg ->
return_http_error(404, "Bad gateway name")
end;
gateway_insta(put, #{
body := GwConf0,
bindings := #{name := Name0}
}) ->
with_gateway(Name0, fun(GwName, _) ->
%% XXX: Clear the unused fields
GwConf = maps:without([<<"name">>], GwConf0),
case emqx_gateway_conf:update_gateway(GwName, GwConf) of
{ok, Gateway} ->
{200, Gateway};
{error, Reason} ->
emqx_gateway_http:reason2resp(Reason)
error:{badconf, _} = Reason1 ->
emqx_gateway_http:reason2resp(Reason1);
throw:not_found ->
return_http_error(404, <<"NOT FOUND">>)
end.
gateway_enable(put, #{bindings := #{name := Name, enable := Enable}}) ->
try
GwName = gw_name(Name),
case emqx_gateway:lookup(GwName) of
undefined ->
return_http_error(404, <<"NOT FOUND">>);
_Gateway ->
{ok, _} = emqx_gateway_conf:update_gateway(GwName, #{<<"enable">> => Enable}),
{204}
end
end).
catch
throw:not_found ->
return_http_error(404, <<"NOT FOUND">>)
end.
-spec gw_name(binary()) -> stomp | coap | lwm2m | mqttsn | exproto | no_return().
gw_name(<<"stomp">>) -> stomp;
gw_name(<<"coap">>) -> coap;
gw_name(<<"lwm2m">>) -> lwm2m;
gw_name(<<"mqttsn">>) -> mqttsn;
gw_name(<<"exproto">>) -> exproto;
gw_name(_Else) -> throw(not_found).
%%--------------------------------------------------------------------
%% Swagger defines
@ -174,7 +175,7 @@ gateway_insta(put, #{
schema("/gateways") ->
#{
'operationId' => gateway,
'operationId' => gateways,
get =>
#{
tags => ?TAGS,
@ -182,29 +183,20 @@ schema("/gateways") ->
summary => <<"List All Gateways">>,
parameters => params_gateway_status_in_qs(),
responses =>
?STANDARD_RESP(
#{
200 => emqx_dashboard_swagger:schema_with_example(
hoconsc:array(ref(gateway_overview)),
examples_gateway_overview()
)
}
)
},
post =>
#{
tags => ?TAGS,
desc => ?DESC(enable_gateway),
summary => <<"Enable a Gateway">>,
%% TODO: distinguish create & response swagger schema
'requestBody' => schema_gateways_conf(),
responses =>
?STANDARD_RESP(#{201 => schema_gateways_conf()})
#{
200 => emqx_dashboard_swagger:schema_with_example(
hoconsc:array(ref(gateway_overview)),
examples_gateway_overview()
),
400 => emqx_dashboard_swagger:error_codes(
[?BAD_REQUEST], <<"Bad request">>
)
}
}
};
schema("/gateways/:name") ->
#{
'operationId' => gateway_insta,
'operationId' => gateway,
get =>
#{
tags => ?TAGS,
@ -212,26 +204,41 @@ schema("/gateways/:name") ->
summary => <<"Get the Gateway">>,
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(#{200 => schema_gateways_conf()})
},
delete =>
#{
tags => ?TAGS,
desc => ?DESC(delete_gateway),
summary => <<"Unload the gateway">>,
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(#{204 => <<"Deleted">>})
#{
200 => schema_gateways_conf(),
404 => emqx_dashboard_swagger:error_codes(
[?NOT_FOUND, ?RESOURCE_NOT_FOUND], <<"Not Found">>
)
}
},
put =>
#{
tags => ?TAGS,
desc => ?DESC(update_gateway),
summary => <<"Update the gateway confs">>,
% [FIXME] add proper desc
summary => <<"Load or update the gateway confs">>,
parameters => params_gateway_name_in_path(),
'requestBody' => schema_update_gateways_conf(),
'requestBody' => schema_load_or_update_gateways_conf(),
responses =>
?STANDARD_RESP(#{200 => schema_gateways_conf()})
?STANDARD_RESP(#{204 => <<"Gateway configuration updated">>})
}
};
schema("/gateways/:name/enable/:enable") ->
#{
'operationId' => gateway_enable,
put =>
#{
tags => ?TAGS,
desc => ?DESC(update_gateway),
summary => <<"Enable or disable gateway">>,
parameters => params_gateway_name_in_path() ++ params_gateway_enable_in_path(),
responses =>
#{
204 => <<"Gateway configuration updated">>,
404 => emqx_dashboard_swagger:error_codes(
[?NOT_FOUND, ?RESOURCE_NOT_FOUND], <<"Not Found">>
)
}
}
};
schema(Path) ->
@ -268,6 +275,18 @@ params_gateway_status_in_qs() ->
)}
].
params_gateway_enable_in_path() ->
[
{enable,
mk(
boolean(),
#{
in => path,
desc => ?DESC(gateway_enable_in_path),
example => true
}
)}
].
%%--------------------------------------------------------------------
%% schemas
@ -377,8 +396,6 @@ fields(Gw) when
->
[{name, mk(Gw, #{desc => ?DESC(gateway_name)})}] ++
convert_listener_struct(emqx_gateway_schema:fields(Gw));
fields(update_disable_enable_only) ->
[{enable, mk(boolean(), #{desc => <<"Enable/Disable the gateway">>})}];
fields(Gw) when
Gw == update_stomp;
Gw == update_mqttsn;
@ -431,15 +448,19 @@ fields(Listener) when
fields(gateway_stats) ->
[{key, mk(binary(), #{})}].
schema_update_gateways_conf() ->
schema_load_or_update_gateways_conf() ->
emqx_dashboard_swagger:schema_with_examples(
hoconsc:union([
ref(?MODULE, stomp),
ref(?MODULE, mqttsn),
ref(?MODULE, coap),
ref(?MODULE, lwm2m),
ref(?MODULE, exproto),
ref(?MODULE, update_stomp),
ref(?MODULE, update_mqttsn),
ref(?MODULE, update_coap),
ref(?MODULE, update_lwm2m),
ref(?MODULE, update_exproto),
ref(?MODULE, update_disable_enable_only)
ref(?MODULE, update_exproto)
]),
examples_update_gateway_confs()
).

View File

@ -23,7 +23,7 @@
emqx_gateway_test_utils,
[
assert_confs/2,
assert_feilds_apperence/2,
assert_fields_exist/2,
request/2,
request/3,
ssl_server_opts/0,
@ -32,6 +32,7 @@
).
-include_lib("eunit/include/eunit.hrl").
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
%% this parses to #{}, will not cause config cleanup
%% so we will need call emqx_config:erase
@ -55,32 +56,68 @@ end_per_suite(Conf) ->
emqx_mgmt_api_test_util:end_suite([emqx_gateway, emqx_authn, emqx_conf]),
Conf.
init_per_testcase(t_gateway_fail, Config) ->
meck:expect(
emqx_gateway_conf,
update_gateway,
fun
(stomp, V) -> {error, {badconf, #{key => gw, value => V, reason => test_error}}};
(coap, V) -> error({badconf, #{key => gw, value => V, reason => test_crash}})
end
),
Config;
init_per_testcase(_, Config) ->
Config.
end_per_testcase(TestCase, Config) ->
case TestCase of
t_gateway_fail -> meck:unload(emqx_gateway_conf);
_ -> ok
end,
[emqx_gateway_conf:unload_gateway(GwName) || GwName <- [stomp, mqttsn, coap, lwm2m, exproto]],
Config.
%%--------------------------------------------------------------------
%% Cases
%%--------------------------------------------------------------------
t_gateway(_) ->
t_gateways(_) ->
{200, Gateways} = request(get, "/gateways"),
lists:foreach(fun assert_gw_unloaded/1, Gateways),
{200, UnloadedGateways} = request(get, "/gateways?status=unloaded"),
lists:foreach(fun assert_gw_unloaded/1, UnloadedGateways),
{200, NoRunningGateways} = request(get, "/gateways?status=running"),
?assertEqual([], NoRunningGateways),
{404, GwNotFoundReq} = request(get, "/gateways/unknown_gateway"),
assert_not_found(GwNotFoundReq),
{400, BadReqInvalidStatus} = request(get, "/gateways?status=invalid_status"),
assert_bad_request(BadReqInvalidStatus),
{400, BadReqUCStatus} = request(get, "/gateways?status=UNLOADED"),
assert_bad_request(BadReqUCStatus),
{201, _} = request(post, "/gateways", #{name => <<"stomp">>}),
{200, StompGw1} = request(get, "/gateways/stomp"),
assert_feilds_apperence(
ok.
t_gateway(_) ->
{404, GwNotFoundReq1} = request(get, "/gateways/not_a_known_atom"),
assert_not_found(GwNotFoundReq1),
{404, GwNotFoundReq2} = request(get, "/gateways/undefined"),
assert_not_found(GwNotFoundReq2),
{204, _} = request(put, "/gateways/stomp", #{}),
{200, StompGw} = request(get, "/gateways/stomp"),
assert_fields_exist(
[name, status, enable, created_at, started_at],
StompGw1
StompGw
),
{204, _} = request(delete, "/gateways/stomp"),
{200, StompGw2} = request(get, "/gateways/stomp"),
assert_gw_unloaded(StompGw2),
{204, _} = request(put, "/gateways/stomp", #{enable => true}),
{200, #{enable := true}} = request(get, "/gateway/stomp"),
{204, _} = request(put, "/gateways/stomp", #{enable => false}),
{200, #{enable := false}} = request(get, "/gateway/stomp"),
{404, _} = request(put, "/gateways/undefined", #{}),
{400, _} = request(put, "/gateways/stomp", #{bad_key => "foo"}),
ok.
t_gateway_fail(_) ->
{204, _} = request(put, "/gateways/stomp", #{}),
{400, _} = request(put, "/gateways/stomp", #{}),
{204, _} = request(put, "/gateways/coap", #{}),
{400, _} = request(put, "/gateways/coap", #{}),
ok.
t_deprecated_gateway(_) ->
@ -88,21 +125,30 @@ t_deprecated_gateway(_) ->
lists:foreach(fun assert_gw_unloaded/1, Gateways),
{404, NotFoundReq} = request(get, "/gateway/uname_gateway"),
assert_not_found(NotFoundReq),
{201, _} = request(post, "/gateway", #{name => <<"stomp">>}),
{200, StompGw1} = request(get, "/gateway/stomp"),
assert_feilds_apperence(
{204, _} = request(put, "/gateway/stomp", #{}),
{200, StompGw} = request(get, "/gateway/stomp"),
assert_fields_exist(
[name, status, enable, created_at, started_at],
StompGw1
StompGw
),
{204, _} = request(delete, "/gateway/stomp"),
{200, StompGw2} = request(get, "/gateway/stomp"),
assert_gw_unloaded(StompGw2),
ok.
t_gateway_enable(_) ->
{204, _} = request(put, "/gateways/stomp", #{}),
{200, #{enable := Enable}} = request(get, "/gateway/stomp"),
NotEnable = not Enable,
{204, _} = request(put, "/gateways/stomp/enable/" ++ atom_to_list(NotEnable), undefined),
{200, #{enable := NotEnable}} = request(get, "/gateway/stomp"),
{204, _} = request(put, "/gateways/stomp/enable/" ++ atom_to_list(Enable), undefined),
{200, #{enable := Enable}} = request(get, "/gateway/stomp"),
{404, _} = request(put, "/gateways/undefined/enable/true", undefined),
{404, _} = request(put, "/gateways/not_a_known_atom/enable/true", undefined),
{404, _} = request(put, "/gateways/coap/enable/true", undefined),
ok.
t_gateway_stomp(_) ->
{200, Gw} = request(get, "/gateways/stomp"),
assert_gw_unloaded(Gw),
%% post
GwConf = #{
name => <<"stomp">>,
frame => #{
@ -114,20 +160,18 @@ t_gateway_stomp(_) ->
#{name => <<"def">>, type => <<"tcp">>, bind => <<"61613">>}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/stomp", GwConf),
{200, ConfResp} = request(get, "/gateways/stomp"),
assert_confs(GwConf, ConfResp),
%% put
GwConf2 = emqx_map_lib:deep_merge(GwConf, #{frame => #{max_headers => 10}}),
{200, _} = request(put, "/gateways/stomp", maps:without([name, listeners], GwConf2)),
{204, _} = request(put, "/gateways/stomp", maps:without([name, listeners], GwConf2)),
{200, ConfResp2} = request(get, "/gateways/stomp"),
assert_confs(GwConf2, ConfResp2),
{204, _} = request(delete, "/gateways/stomp").
ok.
t_gateway_mqttsn(_) ->
{200, Gw} = request(get, "/gateways/mqttsn"),
assert_gw_unloaded(Gw),
%% post
GwConf = #{
name => <<"mqttsn">>,
gateway_id => 1,
@ -138,20 +182,18 @@ t_gateway_mqttsn(_) ->
#{name => <<"def">>, type => <<"udp">>, bind => <<"1884">>}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/mqttsn", GwConf),
{200, ConfResp} = request(get, "/gateways/mqttsn"),
assert_confs(GwConf, ConfResp),
%% put
GwConf2 = emqx_map_lib:deep_merge(GwConf, #{predefined => []}),
{200, _} = request(put, "/gateways/mqttsn", maps:without([name, listeners], GwConf2)),
{204, _} = request(put, "/gateways/mqttsn", maps:without([name, listeners], GwConf2)),
{200, ConfResp2} = request(get, "/gateways/mqttsn"),
assert_confs(GwConf2, ConfResp2),
{204, _} = request(delete, "/gateways/mqttsn").
ok.
t_gateway_coap(_) ->
{200, Gw} = request(get, "/gateways/coap"),
assert_gw_unloaded(Gw),
%% post
GwConf = #{
name => <<"coap">>,
heartbeat => <<"60s">>,
@ -160,20 +202,18 @@ t_gateway_coap(_) ->
#{name => <<"def">>, type => <<"udp">>, bind => <<"5683">>}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/coap", GwConf),
{200, ConfResp} = request(get, "/gateways/coap"),
assert_confs(GwConf, ConfResp),
%% put
GwConf2 = emqx_map_lib:deep_merge(GwConf, #{heartbeat => <<"10s">>}),
{200, _} = request(put, "/gateways/coap", maps:without([name, listeners], GwConf2)),
{204, _} = request(put, "/gateways/coap", maps:without([name, listeners], GwConf2)),
{200, ConfResp2} = request(get, "/gateways/coap"),
assert_confs(GwConf2, ConfResp2),
{204, _} = request(delete, "/gateways/coap").
ok.
t_gateway_lwm2m(_) ->
{200, Gw} = request(get, "/gateways/lwm2m"),
assert_gw_unloaded(Gw),
%% post
GwConf = #{
name => <<"lwm2m">>,
xml_dir => <<"../../lib/emqx_gateway/src/lwm2m/lwm2m_xml">>,
@ -192,20 +232,18 @@ t_gateway_lwm2m(_) ->
#{name => <<"def">>, type => <<"udp">>, bind => <<"5783">>}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/lwm2m", GwConf),
{200, ConfResp} = request(get, "/gateways/lwm2m"),
assert_confs(GwConf, ConfResp),
%% put
GwConf2 = emqx_map_lib:deep_merge(GwConf, #{qmode_time_window => <<"10s">>}),
{200, _} = request(put, "/gateways/lwm2m", maps:without([name, listeners], GwConf2)),
{204, _} = request(put, "/gateways/lwm2m", maps:without([name, listeners], GwConf2)),
{200, ConfResp2} = request(get, "/gateways/lwm2m"),
assert_confs(GwConf2, ConfResp2),
{204, _} = request(delete, "/gateways/lwm2m").
ok.
t_gateway_exproto(_) ->
{200, Gw} = request(get, "/gateways/exproto"),
assert_gw_unloaded(Gw),
%% post
GwConf = #{
name => <<"exproto">>,
server => #{bind => <<"9100">>},
@ -214,15 +252,14 @@ t_gateway_exproto(_) ->
#{name => <<"def">>, type => <<"tcp">>, bind => <<"7993">>}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/exproto", GwConf),
{200, ConfResp} = request(get, "/gateways/exproto"),
assert_confs(GwConf, ConfResp),
%% put
GwConf2 = emqx_map_lib:deep_merge(GwConf, #{server => #{bind => <<"9200">>}}),
{200, _} = request(put, "/gateways/exproto", maps:without([name, listeners], GwConf2)),
{204, _} = request(put, "/gateways/exproto", maps:without([name, listeners], GwConf2)),
{200, ConfResp2} = request(get, "/gateways/exproto"),
assert_confs(GwConf2, ConfResp2),
{204, _} = request(delete, "/gateways/exproto").
ok.
t_gateway_exproto_with_ssl(_) ->
{200, Gw} = request(get, "/gateways/exproto"),
@ -230,7 +267,6 @@ t_gateway_exproto_with_ssl(_) ->
SslSvrOpts = ssl_server_opts(),
SslCliOpts = ssl_client_opts(),
%% post
GwConf = #{
name => <<"exproto">>,
server => #{
@ -245,27 +281,22 @@ t_gateway_exproto_with_ssl(_) ->
#{name => <<"def">>, type => <<"tcp">>, bind => <<"7993">>}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/exproto", GwConf),
{200, ConfResp} = request(get, "/gateways/exproto"),
assert_confs(GwConf, ConfResp),
%% put
GwConf2 = emqx_map_lib:deep_merge(GwConf, #{
server => #{
bind => <<"9200">>,
ssl_options => SslCliOpts
}
}),
{200, _} = request(put, "/gateways/exproto", maps:without([name, listeners], GwConf2)),
{204, _} = request(put, "/gateways/exproto", maps:without([name, listeners], GwConf2)),
{200, ConfResp2} = request(get, "/gateways/exproto"),
assert_confs(GwConf2, ConfResp2),
{204, _} = request(delete, "/gateways/exproto").
ok.
t_authn(_) ->
GwConf = #{name => <<"stomp">>},
{201, _} = request(post, "/gateways", GwConf),
ct:sleep(500),
{204, _} = request(get, "/gateways/stomp/authentication"),
init_gw("stomp"),
AuthConf = #{
mechanism => <<"password_based">>,
backend => <<"built_in_database">>,
@ -283,22 +314,18 @@ t_authn(_) ->
{204, _} = request(delete, "/gateways/stomp/authentication"),
{204, _} = request(get, "/gateways/stomp/authentication"),
{204, _} = request(delete, "/gateways/stomp").
ok.
t_authn_data_mgmt(_) ->
GwConf = #{name => <<"stomp">>},
{201, _} = request(post, "/gateways", GwConf),
ct:sleep(500),
{204, _} = request(get, "/gateways/stomp/authentication"),
init_gw("stomp"),
AuthConf = #{
mechanism => <<"password_based">>,
backend => <<"built_in_database">>,
user_id_type => <<"clientid">>
},
{201, _} = request(post, "/gateways/stomp/authentication", AuthConf),
ct:sleep(500),
{200, ConfResp} = request(get, "/gateways/stomp/authentication"),
{200, ConfResp} =
?retry(10, 10, {200, _} = request(get, "/gateways/stomp/authentication")),
assert_confs(AuthConf, ConfResp),
User1 = #{
@ -358,11 +385,10 @@ t_authn_data_mgmt(_) ->
{204, _} = request(delete, "/gateways/stomp/authentication"),
{204, _} = request(get, "/gateways/stomp/authentication"),
{204, _} = request(delete, "/gateways/stomp").
ok.
t_listeners_tcp(_) ->
GwConf = #{name => <<"stomp">>},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/stomp", #{}),
{404, _} = request(get, "/gateways/stomp/listeners"),
LisConf = #{
name => <<"def">>,
@ -387,7 +413,7 @@ t_listeners_tcp(_) ->
{204, _} = request(delete, "/gateways/stomp/listeners/stomp:tcp:def"),
{404, _} = request(get, "/gateways/stomp/listeners/stomp:tcp:def"),
{204, _} = request(delete, "/gateways/stomp").
ok.
t_listeners_authn(_) ->
GwConf = #{
@ -400,9 +426,7 @@ t_listeners_authn(_) ->
}
]
},
{201, _} = request(post, "/gateways", GwConf),
ct:sleep(500),
{200, ConfResp} = request(get, "/gateways/stomp"),
ConfResp = init_gw("stomp", GwConf),
assert_confs(GwConf, ConfResp),
AuthConf = #{
@ -424,7 +448,7 @@ t_listeners_authn(_) ->
{204, _} = request(delete, Path),
%% FIXME: 204?
{204, _} = request(get, Path),
{204, _} = request(delete, "/gateways/stomp").
ok.
t_listeners_authn_data_mgmt(_) ->
GwConf = #{
@ -437,7 +461,7 @@ t_listeners_authn_data_mgmt(_) ->
}
]
},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(put, "/gateways/stomp", GwConf),
{200, ConfResp} = request(get, "/gateways/stomp"),
assert_confs(GwConf, ConfResp),
@ -514,13 +538,10 @@ t_listeners_authn_data_mgmt(_) ->
{filename, "user-credentials.csv", CSVData}
]),
{204, _} = request(delete, "/gateways/stomp").
ok.
t_authn_fuzzy_search(_) ->
GwConf = #{name => <<"stomp">>},
{201, _} = request(post, "/gateways", GwConf),
{204, _} = request(get, "/gateways/stomp/authentication"),
init_gw("stomp"),
AuthConf = #{
mechanism => <<"password_based">>,
backend => <<"built_in_database">>,
@ -561,7 +582,25 @@ t_authn_fuzzy_search(_) ->
{204, _} = request(delete, "/gateways/stomp/authentication"),
{204, _} = request(get, "/gateways/stomp/authentication"),
{204, _} = request(delete, "/gateways/stomp").
ok.
%%--------------------------------------------------------------------
%% Helpers
init_gw(GwName) ->
init_gw(GwName, #{}).
init_gw(GwName, GwConf) ->
{204, _} = request(put, "/gateways/" ++ GwName, GwConf),
?retry(
10,
10,
begin
{200, #{status := Status} = RespConf} = request(get, "/gateways/" ++ GwName),
false = (Status == <<"unloaded">>),
RespConf
end
).
%%--------------------------------------------------------------------
%% Asserts

View File

@ -94,7 +94,7 @@ maybe_unconvert_listeners(Conf) when is_map(Conf) ->
maybe_unconvert_listeners(Conf) ->
Conf.
assert_feilds_apperence(Ks, Map) ->
assert_fields_exist(Ks, Map) ->
lists:foreach(
fun(K) ->
_ = maps:get(K, Map)

View File

@ -25,7 +25,7 @@
-import(
emqx_gateway_test_utils,
[
assert_feilds_apperence/2,
assert_fields_exist/2,
request/2,
request/3
]
@ -730,7 +730,7 @@ t_rest_clienit_info(_) ->
binary_to_list(ClientId),
{200, StompClient1} = request(get, ClientPath),
?assertEqual(StompClient, StompClient1),
assert_feilds_apperence(
assert_fields_exist(
[
proto_name,
awaiting_rel_max,
@ -787,7 +787,7 @@ t_rest_clienit_info(_) ->
{200, Subs} = request(get, ClientPath ++ "/subscriptions"),
?assertEqual(1, length(Subs)),
assert_feilds_apperence([topic, qos], lists:nth(1, Subs)),
assert_fields_exist([topic, qos], lists:nth(1, Subs)),
{201, _} = request(
post,

View File

@ -10,6 +10,11 @@
- Enhance the `banned` feature [#9367](https://github.com/emqx/emqx/pull/9367).
Now the corresponding session will be kicked when client is banned by `clientid`.
- Redesign `/gateways` API [9364](https://github.com/emqx/emqx/pull/9364).
Use `PUT /gateways/{name}` instead of `POST /gateways`, gateway gets 'loaded'
automatically if needed. Use `PUT /gateways/{name}/enable/{true|false}` to
enable or disable gateway. No more `DELETE /gateways/{name}`.
## Bug fixes
- Return 404 for status of unknown authenticator in `/authenticator/{id}/status` [#9328](https://github.com/emqx/emqx/pull/9328).

View File

@ -10,6 +10,9 @@
- 增加 `封禁` 功能 [#9367](https://github.com/emqx/emqx/pull/9367)。
现在客户端通过 `clientid` 被封禁时将会踢掉对应的会话。
- 重新设计了 /gateways API [9364](https://github.com/emqx/emqx/pull/9364)。
使用 PUT /gateways/{name} 代替了 POST /gateways现在网关将在需要时自动加载然后删除了 DELETE /gateways/{name},之后可以使用 PUT /gateways/{name}/enable/{true|false} 来开启或禁用网关。
## 修复
- 通过 `/authenticator/{id}/status` 请求未知认证器的状态时,将会返回 404。