Explorar o código

fix(emqx_map_lib): ignore non-number non-map values

Zaiming (Stone) Shi %!s(int64=3) %!d(string=hai) anos
pai
achega
5deb0c4878
Modificáronse 2 ficheiros con 96 adicións e 9 borrados
  1. 40 7
      apps/emqx/src/emqx_map_lib.erl
  2. 56 2
      apps/emqx/test/emqx_map_lib_tests.erl

+ 40 - 7
apps/emqx/src/emqx_map_lib.erl

@@ -269,17 +269,50 @@ error_type_two_maps(M1, _M2) ->
 
 
 %% @doc Sum-merge map values.
 %% @doc Sum-merge map values.
 %% For bad merges, ErrorLogger is called to log the key, and value in M2 is ignored.
 %% For bad merges, ErrorLogger is called to log the key, and value in M2 is ignored.
-best_effort_recursive_sum(M1, M2, ErrorLogger) ->
+best_effort_recursive_sum(M10, M20, ErrorLogger) ->
+    FilterF = fun(K, V) ->
+        case erlang:is_number(V) of
+            true ->
+                true;
+            false ->
+                ErrorLogger(#{failed_to_merge => K, bad_value => V}),
+                false
+        end
+    end,
+    M1 = deep_filter(M10, FilterF),
+    M2 = deep_filter(M20, FilterF),
+    do_best_effort_recursive_sum(M1, M2, ErrorLogger).
+
+do_best_effort_recursive_sum(M1, M2, ErrorLogger) ->
     F =
     F =
         fun(Key, V1, V2) ->
         fun(Key, V1, V2) ->
             case {erlang:is_map(V1), erlang:is_map(V2)} of
             case {erlang:is_map(V1), erlang:is_map(V2)} of
                 {true, true} ->
                 {true, true} ->
-                    best_effort_recursive_sum(V1, V2, ErrorLogger);
-                {false, false} when is_number(V1) andalso is_number(V2) ->
-                    V1 + V2;
-                _ ->
-                    ErrorLogger(#{failed_to_merge => Key}),
-                    V1
+                    do_best_effort_recursive_sum(V1, V2, ErrorLogger);
+                {true, false} ->
+                    ErrorLogger(#{failed_to_merge => Key, bad_value => V2}),
+                    do_best_effort_recursive_sum(V1, #{}, ErrorLogger);
+                {false, true} ->
+                    ErrorLogger(#{failed_to_merge => Key, bad_value => V1}),
+                    do_best_effort_recursive_sum(V2, #{}, ErrorLogger);
+                {false, false} ->
+                    true = is_number(V1),
+                    true = is_number(V2),
+                    V1 + V2
             end
             end
         end,
         end,
     merge_with(F, M1, M2).
     merge_with(F, M1, M2).
+
+deep_filter(M, F) when is_map(M) ->
+    %% maps:filtermap is not available before OTP 24
+    maps:from_list(
+        lists:filtermap(
+            fun
+                ({K, V}) when is_map(V) ->
+                    {true, {K, deep_filter(V, F)}};
+                ({K, V}) ->
+                    F(K, V) andalso {true, {K, V}}
+            end,
+            maps:to_list(M)
+        )
+    ).

+ 56 - 2
apps/emqx/test/emqx_map_lib_tests.erl

@@ -49,8 +49,62 @@ best_effort_recursive_sum_test_() ->
             ),
             ),
             receive
             receive
                 {log, Log} ->
                 {log, Log} ->
-                    ?assertEqual(#{failed_to_merge => bar}, Log)
+                    ?assertEqual(#{failed_to_merge => bar, bad_value => bar}, Log)
             after 1000 -> error(timeout)
             after 1000 -> error(timeout)
             end
             end
-        end
+        end,
+        ?_assertEqual(
+            #{},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => foo}, #{foo => bar}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => 1},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => 1}, #{foo => bar}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => 1},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => bar}, #{foo => 1}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => #{bar => 1}},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => #{bar => 1}}, #{foo => 1}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => #{bar => 1}},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => 1}, #{foo => #{bar => 1}}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => #{bar => 1}},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => 1, bar => ignored}, #{foo => #{bar => 1}}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => #{bar => 2}, bar => #{foo => 1}},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => 1, bar => #{foo => 1}}, #{foo => #{bar => 2}, bar => 2}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => #{bar => 2}, bar => #{foo => 1}},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => #{bar => 2}, bar => 2}, #{foo => 1, bar => #{foo => 1}}, DummyLogger
+            )
+        ),
+        ?_assertEqual(
+            #{foo => #{bar => #{}}},
+            emqx_map_lib:best_effort_recursive_sum(
+                #{foo => #{bar => #{foo => []}}}, #{foo => 1}, DummyLogger
+            )
+        )
     ].
     ].