Просмотр исходного кода

feat(connectors api): add dependent actions and sources to response

Fixes https://emqx.atlassian.net/browse/EMQX-12654
Thales Macedo Garitezi 1 год назад
Родитель
Сommit
ae828e8cfb

+ 149 - 4
apps/emqx_bridge/test/emqx_bridge_v2_api_SUITE.erl

@@ -252,23 +252,26 @@ init_per_testcase(TestCase, Config) when
         BridgeConfig
         BridgeConfig
         | Config
         | Config
     ];
     ];
-init_per_testcase(_TestCase, Config) ->
+init_per_testcase(TestCase, Config) ->
     case ?config(cluster_nodes, Config) of
     case ?config(cluster_nodes, Config) of
         undefined ->
         undefined ->
             init_mocks();
             init_mocks();
         Nodes ->
         Nodes ->
             [erpc:call(Node, ?MODULE, init_mocks, []) || Node <- Nodes]
             [erpc:call(Node, ?MODULE, init_mocks, []) || Node <- Nodes]
     end,
     end,
+    ShouldCreateConnector = not lists:member(TestCase, skip_connector_creation_test_cases()),
     case ?config(bridge_kind, Config) of
     case ?config(bridge_kind, Config) of
-        action ->
+        action when ShouldCreateConnector ->
             {ok, 201, _} = request(post, uri(["connectors"]), ?ACTIONS_CONNECTOR, Config);
             {ok, 201, _} = request(post, uri(["connectors"]), ?ACTIONS_CONNECTOR, Config);
-        source ->
+        source when ShouldCreateConnector ->
             {ok, 201, _} = request(
             {ok, 201, _} = request(
                 post,
                 post,
                 uri(["connectors"]),
                 uri(["connectors"]),
                 source_connector_create_config(#{}),
                 source_connector_create_config(#{}),
                 Config
                 Config
-            )
+            );
+        _ ->
+            ok
     end,
     end,
     Config.
     Config.
 
 
@@ -284,6 +287,11 @@ end_per_testcase(_TestCase, Config) ->
     ok = emqx_common_test_helpers:call_janitor(),
     ok = emqx_common_test_helpers:call_janitor(),
     ok.
     ok.
 
 
+skip_connector_creation_test_cases() ->
+    [
+        t_connector_dependencies
+    ].
+
 %%------------------------------------------------------------------------------
 %%------------------------------------------------------------------------------
 %% Helper fns
 %% Helper fns
 %%------------------------------------------------------------------------------
 %%------------------------------------------------------------------------------
@@ -500,6 +508,23 @@ source_config_base() ->
         }
         }
     }.
     }.
 
 
+mqtt_action_config_base() ->
+    source_config_base().
+
+mqtt_action_create_config(Overrides0) ->
+    Overrides = emqx_utils_maps:binary_key_map(Overrides0),
+    Conf0 = maps:merge(
+        mqtt_action_config_base(),
+        #{
+            <<"enable">> => true,
+            <<"type">> => ?SOURCE_TYPE
+        }
+    ),
+    emqx_utils_maps:deep_merge(
+        Conf0,
+        Overrides
+    ).
+
 source_create_config(Overrides0) ->
 source_create_config(Overrides0) ->
     Overrides = emqx_utils_maps:binary_key_map(Overrides0),
     Overrides = emqx_utils_maps:binary_key_map(Overrides0),
     Conf0 = maps:merge(
     Conf0 = maps:merge(
@@ -575,6 +600,32 @@ maybe_get_other_node(Config) ->
             OtherNode
             OtherNode
     end.
     end.
 
 
+list_connectors_api() ->
+    Res = emqx_bridge_v2_testlib:list_connectors_http_api(),
+    emqx_mgmt_api_test_util:simplify_result(Res).
+
+get_connector_api(Type, Name) ->
+    Res = emqx_bridge_v2_testlib:get_connector_api(Type, Name),
+    emqx_mgmt_api_test_util:simplify_result(Res).
+
+create_source_api(Name, Type, Params) ->
+    Res = emqx_bridge_v2_testlib:create_kind_api([
+        {bridge_kind, source},
+        {source_type, Type},
+        {source_name, Name},
+        {source_config, Params}
+    ]),
+    emqx_mgmt_api_test_util:simplify_result(Res).
+
+create_action_api(Name, Type, Params) ->
+    Res = emqx_bridge_v2_testlib:create_kind_api([
+        {bridge_kind, action},
+        {action_type, Type},
+        {action_name, Name},
+        {action_config, Params}
+    ]),
+    emqx_mgmt_api_test_util:simplify_result(Res).
+
 %%------------------------------------------------------------------------------
 %%------------------------------------------------------------------------------
 %% Testcases
 %% Testcases
 %%------------------------------------------------------------------------------
 %%------------------------------------------------------------------------------
@@ -1598,3 +1649,97 @@ t_start_action_or_source_with_disabled_connector(matrix) ->
 t_start_action_or_source_with_disabled_connector(Config) ->
 t_start_action_or_source_with_disabled_connector(Config) ->
     ok = emqx_bridge_v2_testlib:t_start_action_or_source_with_disabled_connector(Config),
     ok = emqx_bridge_v2_testlib:t_start_action_or_source_with_disabled_connector(Config),
     ok.
     ok.
+
+%% Verifies that listing connectors return the actions and sources that depend on the
+%% connector
+t_connector_dependencies(matrix) ->
+    [
+        [single, actions],
+        [single, sources]
+    ];
+t_connector_dependencies(Config) when is_list(Config) ->
+    ?check_trace(
+        begin
+            %% This particular source type happens to serve both actions and sources, a
+            %% nice edge case for this test.
+            ActionType = ?SOURCE_TYPE,
+            ConnectorType = ?SOURCE_CONNECTOR_TYPE,
+            ConnectorName = <<"c">>,
+            {ok, {{_, 201, _}, _, _}} =
+                emqx_bridge_v2_testlib:create_connector_api([
+                    {connector_config, source_connector_create_config(#{})},
+                    {connector_name, ConnectorName},
+                    {connector_type, ConnectorType}
+                ]),
+            ?assertMatch(
+                {200, [
+                    #{
+                        <<"actions">> := [],
+                        <<"sources">> := []
+                    }
+                ]},
+                list_connectors_api()
+            ),
+            ?assertMatch(
+                {200, #{
+                    <<"actions">> := [],
+                    <<"sources">> := []
+                }},
+                get_connector_api(ConnectorType, ConnectorName)
+            ),
+
+            SourceName1 = <<"s1">>,
+            {201, _} = create_source_api(
+                SourceName1,
+                ?SOURCE_TYPE,
+                source_create_config(#{
+                    <<"connector">> => ConnectorName
+                })
+            ),
+            ?assertMatch(
+                {200, [
+                    #{
+                        <<"actions">> := [],
+                        <<"sources">> := [SourceName1]
+                    }
+                ]},
+                list_connectors_api()
+            ),
+            ?assertMatch(
+                {200, #{
+                    <<"actions">> := [],
+                    <<"sources">> := [SourceName1]
+                }},
+                get_connector_api(ConnectorType, ConnectorName)
+            ),
+
+            ActionName1 = <<"a1">>,
+            {201, _} = create_action_api(
+                ActionName1,
+                ActionType,
+                mqtt_action_create_config(#{
+                    <<"connector">> => ConnectorName
+                })
+            ),
+            ?assertMatch(
+                {200, [
+                    #{
+                        <<"actions">> := [ActionName1],
+                        <<"sources">> := [SourceName1]
+                    }
+                ]},
+                list_connectors_api()
+            ),
+            ?assertMatch(
+                {200, #{
+                    <<"actions">> := [ActionName1],
+                    <<"sources">> := [SourceName1]
+                }},
+                get_connector_api(ConnectorType, ConnectorName)
+            ),
+
+            ok
+        end,
+        []
+    ),
+    ok.

+ 16 - 7
apps/emqx_connector/src/emqx_connector_api.erl

@@ -655,7 +655,22 @@ format_resource_data(error, undefined, Result) ->
 format_resource_data(error, Error, Result) ->
 format_resource_data(error, Error, Result) ->
     Result#{status_reason => emqx_utils:readable_error_msg(Error)};
     Result#{status_reason => emqx_utils:readable_error_msg(Error)};
 format_resource_data(channels, Channels, Result) ->
 format_resource_data(channels, Channels, Result) ->
-    Result#{actions => lists:map(fun format_action/1, maps:keys(Channels))};
+    #{
+        actions := Actions,
+        sources := Sources
+    } = lists:foldl(
+        fun(Id, Acc) ->
+            case emqx_bridge_v2:parse_id(Id) of
+                #{kind := source, name := Name} ->
+                    maps:update_with(sources, fun(Ss) -> [Name | Ss] end, Acc);
+                #{name := Name} ->
+                    maps:update_with(actions, fun(As) -> [Name | As] end, Acc)
+            end
+        end,
+        #{actions => [], sources => []},
+        maps:keys(Channels)
+    ),
+    Result#{actions => lists:sort(Actions), sources => lists:sort(Sources)};
 format_resource_data(K, V, Result) ->
 format_resource_data(K, V, Result) ->
     Result#{K => V}.
     Result#{K => V}.
 
 
@@ -673,12 +688,6 @@ unpack_connector_conf(Type, PackedConf) ->
     #{<<"foo">> := RawConf} = maps:get(TypeBin, Bridges),
     #{<<"foo">> := RawConf} = maps:get(TypeBin, Bridges),
     RawConf.
     RawConf.
 
 
-format_action(ActionId) ->
-    case emqx_bridge_v2:parse_id(ActionId) of
-        #{name := Name} ->
-            Name
-    end.
-
 is_ok(ok) ->
 is_ok(ok) ->
     ok;
     ok;
 is_ok(OkResult = {ok, _}) ->
 is_ok(OkResult = {ok, _}) ->

+ 4 - 3
apps/emqx_connector/test/emqx_connector_api_SUITE.erl

@@ -109,9 +109,10 @@
     emqx_conf,
     emqx_conf,
     emqx,
     emqx,
     emqx_auth,
     emqx_auth,
-    emqx_management,
-    {emqx_connector, "connectors {}"},
-    {emqx_bridge, "actions {}"}
+    emqx_connector,
+    emqx_bridge,
+    emqx_rule_engine,
+    emqx_management
 ]).
 ]).
 
 
 -define(APPSPEC_DASHBOARD,
 -define(APPSPEC_DASHBOARD,