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

fix(tpl): ensure backward compat in `emqx_rule_engine`

Missing bindings in string templates will be rendered as "undefined",
as before. Rendering still assumes that missing binding with implicit
default (`undefined`) is an error.

This will also restore complete backward compat in `emqx_prometheus`.
Andrew Mayorov 2 лет назад
Родитель
Сommit
f689d6c233

+ 0 - 2
apps/emqx_connector/src/emqx_connector_template.erl

@@ -340,8 +340,6 @@ lookup(Prop, Bindings) when is_binary(Prop) ->
 
 -spec to_string(binding()) ->
     unicode:chardata().
-to_string(undefined) ->
-    [];
 to_string(Bin) when is_binary(Bin) -> Bin;
 to_string(Num) when is_integer(Num) -> integer_to_binary(Num);
 to_string(Num) when is_float(Num) -> float_to_binary(Num, [{decimals, 10}, compact]);

+ 1 - 1
apps/emqx_connector/test/emqx_connector_template_SUITE.erl

@@ -94,7 +94,7 @@ t_render_missing_bindings(_) ->
         <<"a:${a},b:${b},c:${c},d:${d.d1},e:${no.such_atom_i_swear}">>
     ),
     ?assertEqual(
-        {<<"a:,b:,c:,d:,e:">>, [
+        {<<"a:undefined,b:undefined,c:undefined,d:undefined,e:undefined">>, [
             {"no.such_atom_i_swear", undefined},
             {"d.d1", undefined},
             {"c", undefined},

+ 5 - 4
apps/emqx_rule_engine/src/emqx_rule_actions.erl

@@ -118,10 +118,11 @@ republish(
         }
     }
 ) ->
-    Topic = unicode:characters_to_binary(
-        emqx_connector_template:render_strict(TopicTemplate, Selected)
-    ),
-    Payload = emqx_connector_template:render_strict(PayloadTemplate, Selected),
+    % NOTE: rendering missing bindings as string "undefined"
+    {TopicString, _Errors1} = emqx_connector_template:render(TopicTemplate, Selected),
+    {PayloadString, _Errors2} = emqx_connector_template:render(PayloadTemplate, Selected),
+    Topic = iolist_to_binary(TopicString),
+    Payload = iolist_to_binary(PayloadString),
     QoS = render_simple_var(QoSTemplate, Selected, 0),
     Retain = render_simple_var(RetainTemplate, Selected, false),
     %% 'flags' is set for message re-publishes or message related

+ 27 - 0
apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl

@@ -81,6 +81,7 @@ groups() ->
             t_sqlselect_3,
             t_sqlselect_message_publish_event_keep_original_props_1,
             t_sqlselect_message_publish_event_keep_original_props_2,
+            t_sqlselect_missing_template_vars_render_as_undefined,
             t_sqlparse_event_1,
             t_sqlparse_event_2,
             t_sqlparse_event_3,
@@ -1946,6 +1947,32 @@ t_sqlselect_as_put(_Config) ->
         PayloadMap2
     ).
 
+t_sqlselect_missing_template_vars_render_as_undefined(_Config) ->
+    SQL = <<"SELECT * FROM \"$events/client_connected\"">>,
+    Repub = republish_action(<<"t2">>, <<"${clientid}:${missing.var}">>),
+    {ok, TopicRule} = emqx_rule_engine:create_rule(
+        #{
+            sql => SQL,
+            id => ?TMP_RULEID,
+            actions => [Repub]
+        }
+    ),
+    {ok, Client1} = emqtt:start_link([{clientid, <<"sub-01">>}]),
+    {ok, _} = emqtt:connect(Client1),
+    {ok, _, _} = emqtt:subscribe(Client1, <<"t2">>),
+    {ok, Client2} = emqtt:start_link([{clientid, <<"pub-02">>}]),
+    {ok, _} = emqtt:connect(Client2),
+    emqtt:publish(Client2, <<"foo/bar/1">>, <<>>),
+    receive
+        {publish, Msg} ->
+            ?assertMatch(#{topic := <<"t2">>, payload := <<"pub-02:undefined">>}, Msg)
+    after 2000 ->
+        ct:fail(wait_for_t2)
+    end,
+    emqtt:stop(Client2),
+    emqtt:stop(Client1),
+    delete_rule(TopicRule).
+
 t_sqlparse_event_1(_Config) ->
     Sql =
         "select topic as tp "