Explorar o código

Merge pull request #12118 from thalesmg/fix-missing-type-name-api-actions-r54-20231206

fix(actions_api): add missing fields to API spec and returned data
Thales Macedo Garitezi %!s(int64=2) %!d(string=hai) anos
pai
achega
c274450c5e

+ 16 - 1
apps/emqx_bridge/src/emqx_bridge_v2_api.erl

@@ -799,11 +799,12 @@ format_resource(
         name := Name,
         status := Status,
         error := Error,
-        raw_config := RawConf,
+        raw_config := RawConf0,
         resource_data := _ResourceData
     },
     Node
 ) ->
+    RawConf = fill_defaults(Type, RawConf0),
     redact(
         maps:merge(
             RawConf#{
@@ -934,6 +935,20 @@ aggregate_metrics(
         M17 + N17
     ).
 
+fill_defaults(Type, RawConf) ->
+    PackedConf = pack_bridge_conf(Type, RawConf),
+    FullConf = emqx_config:fill_defaults(emqx_bridge_v2_schema, PackedConf, #{}),
+    unpack_bridge_conf(Type, FullConf).
+
+pack_bridge_conf(Type, RawConf) ->
+    #{<<"actions">> => #{bin(Type) => #{<<"foo">> => RawConf}}}.
+
+unpack_bridge_conf(Type, PackedConf) ->
+    TypeBin = bin(Type),
+    #{<<"actions">> := Bridges} = PackedConf,
+    #{<<"foo">> := RawConf} = maps:get(TypeBin, Bridges),
+    RawConf.
+
 format_bridge_status_and_error(Data) ->
     maps:fold(fun format_resource_data/3, #{}, maps:with([status, error], Data)).
 

+ 14 - 1
apps/emqx_bridge/test/emqx_bridge_v2_api_SUITE.erl

@@ -304,7 +304,7 @@ t_bridges_lifecycle(Config) ->
             <<"status">> := <<"connected">>,
             <<"node_status">> := [_ | _],
             <<"connector">> := ?CONNECTOR_NAME,
-            <<"kafka">> := #{},
+            <<"parameters">> := #{},
             <<"local_topic">> := _,
             <<"resource_opts">> := _
         }},
@@ -1138,6 +1138,19 @@ t_cluster_later_join_metrics(Config) ->
     ),
     ok.
 
+t_raw_config_response_defaults(Config) ->
+    Params = maps:remove(<<"enable">>, ?KAFKA_BRIDGE(?BRIDGE_NAME)),
+    ?assertMatch(
+        {ok, 201, #{<<"enable">> := true}},
+        request_json(
+            post,
+            uri([?ROOT]),
+            Params,
+            Config
+        )
+    ),
+    ok.
+
 %%% helpers
 listen_on_random_port() ->
     SockOpts = [binary, {active, false}, {packet, raw}, {reuseaddr, true}, {backlog, 1000}],

+ 34 - 4
apps/emqx_bridge/test/emqx_bridge_v2_tests.erl

@@ -25,8 +25,8 @@
 non_deprecated_fields(Fields) ->
     [K || {K, Schema} <- Fields, not hocon_schema:is_deprecated(Schema)].
 
-find_resource_opts_fields(SchemaMod, FieldName) ->
-    Fields = hocon_schema:fields(SchemaMod, FieldName),
+find_resource_opts_fields(SchemaMod, StructName) ->
+    Fields = hocon_schema:fields(SchemaMod, StructName),
     case lists:keyfind(resource_opts, 1, Fields) of
         false ->
             undefined;
@@ -35,8 +35,8 @@ find_resource_opts_fields(SchemaMod, FieldName) ->
     end.
 
 get_resource_opts_subfields(Sc) ->
-    ?R_REF(SchemaModRO, FieldNameRO) = hocon_schema:field_schema(Sc, type),
-    ROFields = non_deprecated_fields(hocon_schema:fields(SchemaModRO, FieldNameRO)),
+    ?R_REF(SchemaModRO, StructNameRO) = hocon_schema:field_schema(Sc, type),
+    ROFields = non_deprecated_fields(hocon_schema:fields(SchemaModRO, StructNameRO)),
     proplists:get_keys(ROFields).
 
 %%------------------------------------------------------------------------------
@@ -107,3 +107,33 @@ connector_resource_opts_test() ->
         }
     ),
     ok.
+
+actions_api_spec_post_fields_test() ->
+    ?UNION(Union) = emqx_bridge_v2_schema:post_request(),
+    Schemas =
+        lists:map(
+            fun(?R_REF(SchemaMod, StructName)) ->
+                {SchemaMod, hocon_schema:fields(SchemaMod, StructName)}
+            end,
+            hoconsc:union_members(Union)
+        ),
+    MinimalFields0 =
+        [
+            binary_to_atom(F)
+         || F <- emqx_bridge_v2_schema:top_level_common_action_keys(),
+            F =/= <<"local_topic">>
+        ],
+    MinimalFields = [type, name | MinimalFields0],
+    MissingFields =
+        lists:filtermap(
+            fun({SchemaMod, FieldSchemas}) ->
+                Missing = MinimalFields -- proplists:get_keys(FieldSchemas),
+                case Missing of
+                    [] -> false;
+                    _ -> {true, {SchemaMod, Missing}}
+                end
+            end,
+            Schemas
+        ),
+    ?assertEqual(#{}, maps:from_list(MissingFields)),
+    ok.

+ 3 - 2
apps/emqx_bridge_matrix/src/emqx_bridge_matrix.erl

@@ -23,6 +23,7 @@
 ]).
 
 -define(CONNECTOR_TYPE, matrix).
+-define(ACTION_TYPE, matrix).
 
 %% -------------------------------------------------------------------------------------------------
 %% api
@@ -44,7 +45,7 @@ namespace() -> "bridge_matrix".
 roots() -> [].
 
 fields("post") ->
-    emqx_bridge_pgsql:fields("post", matrix);
+    emqx_bridge_pgsql:fields("post", ?ACTION_TYPE, "config");
 fields("config_connector") ->
     emqx_bridge_pgsql:fields("config_connector");
 fields(action) ->
@@ -61,7 +62,7 @@ fields("put_bridge_v2") ->
 fields("get_bridge_v2") ->
     emqx_bridge_pgsql:fields(pgsql_action);
 fields("post_bridge_v2") ->
-    emqx_bridge_pgsql:fields(pgsql_action);
+    emqx_bridge_pgsql:fields("post", ?ACTION_TYPE, pgsql_action);
 fields(Field) when
     Field == "get_connector";
     Field == "put_connector";

+ 9 - 9
apps/emqx_bridge_pgsql/src/emqx_bridge_pgsql.erl

@@ -13,13 +13,15 @@
 -include_lib("snabbkaffe/include/snabbkaffe.hrl").
 -include_lib("emqx_resource/include/emqx_resource.hrl").
 
+%% `hocon_schema' API
 -export([
     namespace/0,
     roots/0,
     fields/1,
-    desc/1,
-    fields/2
+    desc/1
 ]).
+%% for sharing with other actions
+-export([fields/3]).
 
 %% Examples
 -export([
@@ -33,9 +35,7 @@
     values_conn_bridge_examples/2
 ]).
 
--define(PGSQL_HOST_OPTIONS, #{
-    default_port => ?PGSQL_DEFAULT_PORT
-}).
+-define(ACTION_TYPE, pgsql).
 
 %% Hocon Schema Definitions
 namespace() -> "bridge_pgsql".
@@ -81,7 +81,7 @@ fields("put_bridge_v2") ->
 fields("get_bridge_v2") ->
     fields(pgsql_action);
 fields("post_bridge_v2") ->
-    fields(pgsql_action);
+    fields("post", pgsql, pgsql_action);
 fields("config") ->
     [
         {enable, hoconsc:mk(boolean(), #{desc => ?DESC("config_enable"), default => true})},
@@ -99,14 +99,14 @@ fields("config") ->
         (emqx_postgresql:fields(config) --
             emqx_connector_schema_lib:prepare_statement_fields());
 fields("post") ->
-    fields("post", pgsql);
+    fields("post", ?ACTION_TYPE, "config");
 fields("put") ->
     fields("config");
 fields("get") ->
     emqx_bridge_schema:status_fields() ++ fields("post").
 
-fields("post", Type) ->
-    [type_field(Type), name_field() | fields("config")].
+fields("post", Type, StructName) ->
+    [type_field(Type), name_field() | fields(StructName)].
 
 type_field(Type) ->
     {type, hoconsc:mk(hoconsc:enum([Type]), #{required => true, desc => ?DESC("desc_type")})}.

+ 3 - 2
apps/emqx_bridge_timescale/src/emqx_bridge_timescale.erl

@@ -23,6 +23,7 @@
 ]).
 
 -define(CONNECTOR_TYPE, timescale).
+-define(ACTION_TYPE, timescale).
 
 %% -------------------------------------------------------------------------------------------------
 %% api
@@ -44,7 +45,7 @@ namespace() -> "bridge_timescale".
 roots() -> [].
 
 fields("post") ->
-    emqx_bridge_pgsql:fields("post", timescale);
+    emqx_bridge_pgsql:fields("post", ?ACTION_TYPE, "config");
 fields("config_connector") ->
     emqx_postgresql_connector_schema:fields("config_connector");
 fields(action) ->
@@ -61,7 +62,7 @@ fields("put_bridge_v2") ->
 fields("get_bridge_v2") ->
     emqx_bridge_pgsql:fields(pgsql_action);
 fields("post_bridge_v2") ->
-    emqx_bridge_pgsql:fields(pgsql_action);
+    emqx_bridge_pgsql:fields("post", ?ACTION_TYPE, pgsql_action);
 fields(Field) when
     Field == "get_connector";
     Field == "put_connector";

+ 2 - 2
apps/emqx_connector/test/emqx_connector_api_SUITE.erl

@@ -766,7 +766,7 @@ t_actions_field(Config) ->
             <<"status">> := <<"connected">>,
             <<"node_status">> := [_ | _],
             <<"connector">> := Name,
-            <<"kafka">> := #{},
+            <<"parameters">> := #{},
             <<"local_topic">> := _,
             <<"resource_opts">> := _
         }},
@@ -821,7 +821,7 @@ t_fail_delete_with_action(Config) ->
             <<"status">> := <<"connected">>,
             <<"node_status">> := [_ | _],
             <<"connector">> := Name,
-            <<"kafka">> := #{},
+            <<"parameters">> := #{},
             <<"local_topic">> := _,
             <<"resource_opts">> := _
         }},