aboutsummaryrefslogtreecommitdiffstats
path: root/lib/common_test/src/ct_rpc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common_test/src/ct_rpc.erl')
-rw-r--r--lib/common_test/src/ct_rpc.erl204
1 files changed, 204 insertions, 0 deletions
diff --git a/lib/common_test/src/ct_rpc.erl b/lib/common_test/src/ct_rpc.erl
new file mode 100644
index 0000000000..03d95d1408
--- /dev/null
+++ b/lib/common_test/src/ct_rpc.erl
@@ -0,0 +1,204 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%% @doc Common Test specific layer on Erlang/OTP rpc.
+
+-module(ct_rpc).
+
+%%% API
+-export([app_node/2, app_node/3, app_node/4,
+ call/4, call/5, call/6, cast/4, cast/5]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+%%% @spec app_node(App, Candidates) -> NodeName
+%%%
+%%% App = atom()
+%%% Candidates = [NodeName]
+%%% NodeName = atom()
+%%%
+%%% @doc From a set of candidate nodes determines which of them is
+%%% running the application App. If none of the candidate nodes
+%%% is running the application the function will make the test case
+%%% calling this function fail. This function is the same as calling
+%%% <code>app_node(App, Candidates, true)</code>.
+%%%
+app_node(App, Candidates) ->
+ app_node(App, Candidates, true, []).
+
+%%% @spec app_node(App, Candidates, FailOnBadRPC) -> NodeName
+%%%
+%%% App = atom()
+%%% Candidates = [NodeName]
+%%% NodeName = atom()
+%%% FailOnBadRPC = true | false
+%%%
+%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code>
+%%% argument will determine if the search for a candidate node should
+%%% stop or not if <code>badrpc</code> is received at some point.
+%%%
+app_node(App, Candidates, FailOnBadRPC) ->
+ app_node(App, Candidates, FailOnBadRPC, []).
+
+%%% @spec app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName
+%%%
+%%% App = atom()
+%%% Candidates = [NodeName]
+%%% NodeName = atom()
+%%% FailOnBadRPC = true | false
+%%% Cookie = atom()
+%%%
+%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code>
+%%% argument will determine if the search for a candidate node should
+%%% stop or not if <code>badrpc</code> is received at some point.
+%%% The cookie on the client node will be set to <code>Cookie</code>
+%%% for this rpc operation (use to match the server node cookie).
+%%%
+app_node(App, [], _, _) ->
+ ct:fail({application_not_running, App});
+
+%% Variable _Candidates is a workaround for the strange edoc behavior
+%% of creating the spec: app_node(App, Nodes::Candidates) -> NodeName
+%% if it does not exist.
+app_node(App, _Candidates = [CandidateNode | Nodes], FailOnBadRPC, Cookie) ->
+ Cookie0 = set_the_cookie(Cookie),
+ Result = rpc:call(CandidateNode, application, which_applications, []),
+ set_the_cookie(Cookie0),
+ case Result of
+ {badrpc,Reason} when FailOnBadRPC == true ->
+ ct:fail({Reason,CandidateNode});
+ {badrpc,_} when FailOnBadRPC == false ->
+ app_node(App, Nodes, FailOnBadRPC);
+ Apps ->
+ case lists:keysearch(App, 1, Apps) of
+ {value, _} ->
+ CandidateNode;
+ _ ->
+ app_node(App, Nodes, FailOnBadRPC)
+ end
+ end.
+
+%%% @spec call(Node, Module, Function, Args) -> term() | {badrpc, Reason}
+%%%
+%%% @doc Same as call(Node, Module, Function, Args, infinity)
+%%%
+call(Node, Module, Function, Args) ->
+ call(Node, Module, Function, Args, infinity, []).
+
+%%% @spec call(Node, Module, Function, Args, TimeOut) ->
+%%% term() | {badrpc, Reason}
+%%% Node = NodeName | {Fun, FunArgs}
+%%% Fun = fun()
+%%% FunArgs = term()
+%%% NodeName = atom()
+%%% Module = atom()
+%%% Function = atom()
+%%% Args = [term()]
+%%% Reason = timeout | term()
+%%%
+%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
+%%% Returns whatever Function returns or {badrpc, Reason} if the
+%%% remote procedure call fails. If Node is {Fun, FunArgs} applying
+%%% Fun to FunArgs should return a node name.
+call(Node, Module, Function, Args, TimeOut) ->
+ call(Node, Module, Function, Args, TimeOut, []).
+
+%%% @spec call(Node, Module, Function, Args, TimeOut, Cookie) ->
+%%% term() | {badrpc, Reason}
+%%% Node = NodeName | {Fun, FunArgs}
+%%% Fun = fun()
+%%% FunArgs = term()
+%%% NodeName = atom()
+%%% Module = atom()
+%%% Function = atom()
+%%% Args = [term()]
+%%% Reason = timeout | term()
+%%% Cookie = atom()
+%%%
+%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
+%%% Returns whatever Function returns or {badrpc, Reason} if the
+%%% remote procedure call fails. If Node is {Fun, FunArgs} applying
+%%% Fun to FunArgs should return a node name.
+%%% The cookie on the client node will be set to <code>Cookie</code>
+%%% for this rpc operation (use to match the server node cookie).
+call({Fun, FunArgs}, Module, Function, Args, TimeOut, Cookie) ->
+ Node = Fun(FunArgs),
+ call(Node, Module, Function, Args, TimeOut, Cookie);
+call(Node, Module, Function, Args, TimeOut, Cookie) when is_atom(Node) ->
+ Cookie0 = set_the_cookie(Cookie),
+ Result = rpc:call(Node, Module, Function, Args, TimeOut),
+ set_the_cookie(Cookie0),
+ Result.
+
+%%% @spec cast(Node, Module, Function, Args) -> ok
+%%% Node = NodeName | {Fun, FunArgs}
+%%% Fun = fun()
+%%% FunArgs = term()
+%%% NodeName = atom()
+%%% Module = atom()
+%%% Function = atom()
+%%% Args = [term()]
+%%% Reason = timeout | term()
+%%%
+%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
+%%% No response is delivered and the process which makes the call is
+%%% not suspended until the evaluation is compleated as in the case of
+%%% call/[3,4]. If Node is {Fun, FunArgs} applying
+%%% Fun to FunArgs should return a node name.
+cast(Node, Module, Function, Args) ->
+ cast(Node, Module, Function, Args, []).
+
+%%% @spec cast(Node, Module, Function, Args, Cookie) -> ok
+%%% Node = NodeName | {Fun, FunArgs}
+%%% Fun = fun()
+%%% FunArgs = term()
+%%% NodeName = atom()
+%%% Module = atom()
+%%% Function = atom()
+%%% Args = [term()]
+%%% Reason = timeout | term()
+%%% Cookie = atom()
+%%%
+%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
+%%% No response is delivered and the process which makes the call is
+%%% not suspended until the evaluation is compleated as in the case of
+%%% call/[3,4]. If Node is {Fun, FunArgs} applying
+%%% Fun to FunArgs should return a node name.
+%%% The cookie on the client node will be set to <code>Cookie</code>
+%%% for this rpc operation (use to match the server node cookie).
+cast({Fun, FunArgs}, Module, Function, Args, Cookie) ->
+ Node = Fun(FunArgs),
+ cast(Node, Module, Function, Args, Cookie);
+cast(Node, Module, Function, Args, Cookie) when is_atom(Node) ->
+ Cookie0 = set_the_cookie(Cookie),
+ true = rpc:cast(Node, Module, Function, Args),
+ set_the_cookie(Cookie0),
+ ok.
+
+
+%%%---------- Internal -----------
+
+%%% @hidden
+set_the_cookie([]) ->
+ [];
+set_the_cookie(Cookie) ->
+ Cookie0 = erlang:get_cookie(),
+ erlang:set_cookie(node(),Cookie),
+ Cookie0.