feat(actions_api): add `/action_types` API

This commit is contained in:
Thales Macedo Garitezi 2023-11-09 13:54:57 -03:00
parent a828eea613
commit eabd09051a
4 changed files with 78 additions and 5 deletions

View File

@ -40,7 +40,8 @@
'/actions/:id/enable/:enable'/2,
'/actions/:id/:operation'/2,
'/nodes/:node/actions/:id/:operation'/2,
'/actions_probe'/2
'/actions_probe'/2,
'/action_types'/2
]).
%% BpAPI
@ -79,7 +80,8 @@ paths() ->
"/actions/:id/enable/:enable",
"/actions/:id/:operation",
"/nodes/:node/actions/:id/:operation",
"/actions_probe"
"/actions_probe",
"/action_types"
].
error_schema(Code, Message) when is_atom(Code) ->
@ -338,6 +340,27 @@ schema("/actions_probe") ->
400 => error_schema(['TEST_FAILED'], "bridge test failed")
}
}
};
schema("/action_types") ->
#{
'operationId' => '/action_types',
get => #{
tags => [<<"actions">>],
desc => ?DESC("desc_api10"),
summary => <<"List available action types">>,
responses => #{
200 => emqx_dashboard_swagger:schema_with_examples(
array(emqx_bridge_v2_schema:types_sc()),
#{
<<"types">> =>
#{
summary => <<"Action types">>,
value => emqx_bridge_v2_schema:types()
}
}
)
}
}
}.
'/actions'(post, #{body := #{<<"type">> := BridgeType, <<"name">> := BridgeName} = Conf0}) ->
@ -486,6 +509,9 @@ schema("/actions_probe") ->
redact(BadRequest)
end.
'/action_types'(get, _Request) ->
?OK(emqx_bridge_v2_schema:types()).
maybe_deobfuscate_bridge_probe(#{<<"type">> := BridgeType, <<"name">> := BridgeName} = Params) ->
case emqx_bridge:lookup(BridgeType, BridgeName) of
{ok, #{raw_config := RawConf}} ->

View File

@ -30,9 +30,18 @@
post_request/0
]).
-export([types/0, types_sc/0]).
-export([enterprise_api_schemas/1]).
-export_type([action_type/0]).
%% Should we explicitly list them here so dialyzer may be more helpful?
-type action_type() :: atom().
-if(?EMQX_RELEASE_EDITION == ee).
-spec enterprise_api_schemas(Method) -> [{_Type :: binary(), ?R_REF(module(), Method)}] when
Method :: string().
enterprise_api_schemas(Method) ->
%% We *must* do this to ensure the module is really loaded, especially when we use
%% `call_hocon' from `nodetool' to generate initial configurations.
@ -55,6 +64,8 @@ enterprise_fields_actions() ->
-else.
-spec enterprise_api_schemas(Method) -> [{_Type :: binary(), ?R_REF(module(), Method)}] when
Method :: string().
enterprise_api_schemas(_Method) -> [].
enterprise_fields_actions() -> [].
@ -129,6 +140,14 @@ desc(actions) ->
desc(_) ->
undefined.
-spec types() -> [action_type()].
types() ->
proplists:get_keys(?MODULE:fields(actions)).
-spec types_sc() -> ?ENUM([action_type()]).
types_sc() ->
hoconsc:enum(types()).
-ifdef(TEST).
-include_lib("hocon/include/hocon_types.hrl").
schema_homogeneous_test() ->

View File

@ -236,6 +236,14 @@ end_per_group(_, Config) ->
emqx_cth_suite:stop(?config(group_apps, Config)),
ok.
init_per_testcase(t_action_types, Config) ->
case ?config(cluster_nodes, Config) of
undefined ->
init_mocks();
Nodes ->
[erpc:call(Node, ?MODULE, init_mocks, []) || Node <- Nodes]
end,
Config;
init_per_testcase(_TestCase, Config) ->
case ?config(cluster_nodes, Config) of
undefined ->
@ -260,8 +268,14 @@ end_per_testcase(_TestCase, Config) ->
-define(CONNECTOR_IMPL, emqx_bridge_v2_dummy_connector).
init_mocks() ->
meck:new(emqx_connector_ee_schema, [passthrough, no_link]),
meck:expect(emqx_connector_ee_schema, resource_type, 1, ?CONNECTOR_IMPL),
case emqx_release:edition() of
ee ->
meck:new(emqx_connector_ee_schema, [passthrough, no_link]),
meck:expect(emqx_connector_ee_schema, resource_type, 1, ?CONNECTOR_IMPL),
ok;
ce ->
ok
end,
meck:new(?CONNECTOR_IMPL, [non_strict, no_link]),
meck:expect(?CONNECTOR_IMPL, callback_mode, 0, async_if_possible),
meck:expect(
@ -289,7 +303,7 @@ init_mocks() ->
ok = meck:expect(?CONNECTOR_IMPL, on_get_channels, fun(ResId) ->
emqx_bridge_v2:get_channels_for_connector(ResId)
end),
[?CONNECTOR_IMPL, emqx_connector_ee_schema].
ok.
clear_resources() ->
lists:foreach(
@ -886,6 +900,14 @@ t_cascade_delete_actions(Config) ->
),
{ok, 200, []} = request_json(get, uri([?ROOT]), Config).
t_action_types(Config) ->
Res = request_json(get, uri(["action_types"]), Config),
?assertMatch({ok, 200, _}, Res),
{ok, 200, Types} = Res,
?assert(is_list(Types), #{types => Types}),
?assert(lists:all(fun is_binary/1, Types), #{types => Types}),
ok.
%%% helpers
listen_on_random_port() ->
SockOpts = [binary, {active, false}, {packet, raw}, {reuseaddr, true}, {backlog, 1000}],

View File

@ -54,6 +54,12 @@ desc_api9.desc:
desc_api9.label:
"""Test Bridge Creation"""
desc_api10.desc:
"""Lists the available action types."""
desc_api10.label:
"""List action types"""
desc_bridge_metrics.desc:
"""Get bridge metrics by id."""