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

test: refactor emqx_rpc unit tests

Zaiming (Stone) Shi 2 лет назад
Родитель
Сommit
6e8c73258f
2 измененных файлов с 79 добавлено и 203 удалено
  1. 79 8
      apps/emqx/src/emqx_rpc.erl
  2. 0 195
      apps/emqx/test/props/prop_emqx_rpc.erl

+ 79 - 8
apps/emqx/src/emqx_rpc.erl

@@ -43,6 +43,10 @@
     erpc_multicall/1
 ]).
 
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
+
 -compile(
     {inline, [
         rpc_node/1,
@@ -75,15 +79,15 @@
 
 -spec call(node(), module(), atom(), list()) -> call_result().
 call(Node, Mod, Fun, Args) ->
-    filter_result(gen_rpc:call(rpc_node(Node), Mod, Fun, Args)).
+    maybe_badrpc(gen_rpc:call(rpc_node(Node), Mod, Fun, Args)).
 
 -spec call(term(), node(), module(), atom(), list()) -> call_result().
 call(Key, Node, Mod, Fun, Args) ->
-    filter_result(gen_rpc:call(rpc_node({Key, Node}), Mod, Fun, Args)).
+    maybe_badrpc(gen_rpc:call(rpc_node({Key, Node}), Mod, Fun, Args)).
 
 -spec call(term(), node(), module(), atom(), list(), timeout()) -> call_result().
 call(Key, Node, Mod, Fun, Args, Timeout) ->
-    filter_result(gen_rpc:call(rpc_node({Key, Node}), Mod, Fun, Args, Timeout)).
+    maybe_badrpc(gen_rpc:call(rpc_node({Key, Node}), Mod, Fun, Args, Timeout)).
 
 -spec multicall([node()], module(), atom(), list()) -> multicall_result().
 multicall(Nodes, Mod, Fun, Args) ->
@@ -127,18 +131,15 @@ rpc_nodes([], Acc) ->
 rpc_nodes([Node | Nodes], Acc) ->
     rpc_nodes(Nodes, [rpc_node(Node) | Acc]).
 
-filter_result({Error, Reason}) when
-    Error =:= badrpc; Error =:= badtcp
-->
+maybe_badrpc({Error, Reason}) when Error =:= badrpc; Error =:= badtcp ->
     {badrpc, Reason};
-filter_result(Delivery) ->
+maybe_badrpc(Delivery) ->
     Delivery.
 
 max_client_num() ->
     emqx:get_config([rpc, tcp_client_num], ?DefaultClientNum).
 
 -spec unwrap_erpc(emqx_rpc:erpc(A) | [emqx_rpc:erpc(A)]) -> A | {error, _Err} | list().
-
 unwrap_erpc(Res) when is_list(Res) ->
     [unwrap_erpc(R) || R <- Res];
 unwrap_erpc({ok, A}) ->
@@ -151,3 +152,73 @@ unwrap_erpc({exit, Err}) ->
     {error, Err};
 unwrap_erpc({error, {erpc, Err}}) ->
     {error, Err}.
+
+-ifdef(TEST).
+
+badrpc_call_test_() ->
+    application:ensure_all_started(gen_rpc),
+    Node = node(),
+    [
+        {"throw", fun() ->
+            ?assertEqual(foo, call(Node, erlang, throw, [foo]))
+        end},
+        {"error", fun() ->
+            ?assertMatch({badrpc, {'EXIT', {foo, _}}}, call(Node, erlang, error, [foo]))
+        end},
+        {"exit", fun() ->
+            ?assertEqual({badrpc, {'EXIT', foo}}, call(Node, erlang, exit, [foo]))
+        end},
+        {"timeout", fun() ->
+            ?assertEqual({badrpc, timeout}, call(key, Node, timer, sleep, [1000], 100))
+        end},
+        {"noconnection", fun() ->
+            %% mute crash report from gen_rpc
+            logger:set_primary_config(level, critical),
+            try
+                ?assertEqual(
+                    {badrpc, nxdomain}, call(key, 'no@such.node', foo, bar, [])
+                )
+            after
+                logger:set_primary_config(level, notice)
+            end
+        end}
+    ].
+
+multicall_test() ->
+    application:ensure_all_started(gen_rpc),
+    logger:set_primary_config(level, critical),
+    BadNode = 'no@such.node',
+    ThisNode = node(),
+    Nodes = [ThisNode, BadNode],
+    Call4 = fun(M, F, A) -> multicall(Nodes, M, F, A) end,
+    Call5 = fun(Key, M, F, A) -> multicall(Key, Nodes, M, F, A) end,
+    try
+        ?assertMatch({[foo], [{BadNode, _}]}, Call4(erlang, throw, [foo])),
+        ?assertMatch({[], [{ThisNode, _}, {BadNode, _}]}, Call4(erlang, error, [foo])),
+        ?assertMatch({[], [{ThisNode, _}, {BadNode, _}]}, Call4(erlang, exit, [foo])),
+        ?assertMatch({[], [{ThisNode, _}, {BadNode, _}]}, Call5(key, foo, bar, []))
+    after
+        logger:set_primary_config(level, notice)
+    end.
+
+unwrap_erpc_test_() ->
+    Nodes = [node()],
+    MultiC = fun(M, F, A) -> unwrap_erpc(erpc:multicall(Nodes, M, F, A, 100)) end,
+    [
+        {"throw", fun() ->
+            ?assertEqual([{error, foo}], MultiC(erlang, throw, [foo]))
+        end},
+        {"error", fun() ->
+            ?assertEqual([{error, foo}], MultiC(erlang, error, [foo]))
+        end},
+        {"exit", fun() ->
+            ?assertEqual([{error, {exception, foo}}], MultiC(erlang, exit, [foo]))
+        end},
+        {"noconnection", fun() ->
+            ?assertEqual(
+                [{error, noconnection}], unwrap_erpc(erpc:multicall(['no@such.node'], foo, bar, []))
+            )
+        end}
+    ].
+
+-endif.

+ 0 - 195
apps/emqx/test/props/prop_emqx_rpc.erl

@@ -1,195 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%%     http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%--------------------------------------------------------------------
-
--module(prop_emqx_rpc).
-
--include_lib("proper/include/proper.hrl").
--include_lib("eunit/include/eunit.hrl").
-
--define(NODENAME, 'test@127.0.0.1').
-
--define(ALL(Vars, Types, Exprs),
-    ?SETUP(
-        fun() ->
-            State = do_setup(),
-            fun() -> do_teardown(State) end
-        end,
-        ?FORALL(Vars, Types, Exprs)
-    )
-).
-
-%%--------------------------------------------------------------------
-%% Properties
-%%--------------------------------------------------------------------
-
-prop_node() ->
-    ?ALL(
-        Node0,
-        nodename(),
-        begin
-            Node = punch(Node0),
-            ?assert(emqx_rpc:cast(Node, erlang, system_time, [])),
-            case emqx_rpc:call(Node, erlang, system_time, []) of
-                {badrpc, _Reason} -> true;
-                Delivery when is_integer(Delivery) -> true;
-                _Other -> false
-            end
-        end
-    ).
-
-prop_node_with_key() ->
-    ?ALL(
-        {Node0, Key},
-        nodename_with_key(),
-        begin
-            Node = punch(Node0),
-            ?assert(emqx_rpc:cast(Key, Node, erlang, system_time, [])),
-            case emqx_rpc:call(Key, Node, erlang, system_time, []) of
-                {badrpc, _Reason} -> true;
-                Delivery when is_integer(Delivery) -> true;
-                _Other -> false
-            end
-        end
-    ).
-
-prop_nodes() ->
-    ?ALL(
-        Nodes0,
-        nodesname(),
-        begin
-            Nodes = punch(Nodes0),
-            case emqx_rpc:multicall(Nodes, erlang, system_time, []) of
-                {RealResults, RealBadNodes} when
-                    is_list(RealResults);
-                    is_list(RealBadNodes)
-                ->
-                    true;
-                _Other ->
-                    false
-            end
-        end
-    ).
-
-prop_nodes_with_key() ->
-    ?ALL(
-        {Nodes0, Key},
-        nodesname_with_key(),
-        begin
-            Nodes = punch(Nodes0),
-            case emqx_rpc:multicall(Key, Nodes, erlang, system_time, []) of
-                {RealResults, RealBadNodes} when
-                    is_list(RealResults);
-                    is_list(RealBadNodes)
-                ->
-                    true;
-                _Other ->
-                    false
-            end
-        end
-    ).
-
-%%--------------------------------------------------------------------
-%%  Helper
-%%--------------------------------------------------------------------
-
-do_setup() ->
-    ensure_distributed_nodename(),
-    ok = logger:set_primary_config(#{level => warning}),
-    {ok, _Apps} = application:ensure_all_started(gen_rpc),
-    ok = application:set_env(gen_rpc, call_receive_timeout, 100),
-    ok = meck:new(gen_rpc, [passthrough, no_history]),
-    ok = meck:expect(
-        gen_rpc,
-        multicall,
-        fun(Nodes, Mod, Fun, Args) ->
-            gen_rpc:multicall(Nodes, Mod, Fun, Args, 100)
-        end
-    ).
-
-do_teardown(_) ->
-    ok = net_kernel:stop(),
-    ok = application:stop(gen_rpc),
-    ok = meck:unload(gen_rpc),
-    %% wait for tcp close
-    timer:sleep(2500).
-
-ensure_distributed_nodename() ->
-    case net_kernel:start([?NODENAME]) of
-        {ok, _} ->
-            ok;
-        {error, {already_started, _}} ->
-            net_kernel:stop(),
-            net_kernel:start([?NODENAME]);
-        {error, {{shutdown, {_, _, {'EXIT', nodistribution}}}, _}} ->
-            %% start epmd first
-            spawn_link(fun() -> os:cmd("epmd") end),
-            timer:sleep(100),
-            net_kernel:start([?NODENAME])
-    end.
-
-%%--------------------------------------------------------------------
-%% Generator
-%%--------------------------------------------------------------------
-
-nodename() ->
-    ?LET(
-        {NodePrefix, HostName},
-        {node_prefix(), hostname()},
-        begin
-            Node = NodePrefix ++ "@" ++ HostName,
-            list_to_atom(Node)
-        end
-    ).
-
-nodename_with_key() ->
-    ?LET(
-        {NodePrefix, HostName, Key},
-        {node_prefix(), hostname(), choose(0, 10)},
-        begin
-            Node = NodePrefix ++ "@" ++ HostName,
-            {list_to_atom(Node), Key}
-        end
-    ).
-
-nodesname() ->
-    oneof([list(nodename()), [node()]]).
-
-nodesname_with_key() ->
-    oneof([{list(nodename()), choose(0, 10)}, {[node()], 1}]).
-
-node_prefix() ->
-    oneof(["emqxct", text_like()]).
-
-text_like() ->
-    ?SUCHTHAT(Text, list(range($a, $z)), (length(Text) =< 100 andalso length(Text) > 0)).
-
-hostname() ->
-    oneof(["127.0.0.1", "localhost"]).
-
-%%--------------------------------------------------------------------
-%% Utils
-%%--------------------------------------------------------------------
-
-%% After running the props, the `node()` () is only able to return an
-%% incorrect node name - `nonode@nohost`, But we want a distributed nodename
-%% So, just translate the `nonode@nohost` to ?NODENAME
-punch(Nodes) when is_list(Nodes) ->
-    lists:map(fun punch/1, Nodes);
-punch('nonode@nohost') ->
-    %% Equal to ?NODENAME
-    node();
-punch(GoodBoy) ->
-    GoodBoy.