aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/test/megaco_tcp_test.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/megaco/test/megaco_tcp_test.erl')
-rw-r--r--lib/megaco/test/megaco_tcp_test.erl1253
1 files changed, 1253 insertions, 0 deletions
diff --git a/lib/megaco/test/megaco_tcp_test.erl b/lib/megaco/test/megaco_tcp_test.erl
new file mode 100644
index 0000000000..31c88489fe
--- /dev/null
+++ b/lib/megaco/test/megaco_tcp_test.erl
@@ -0,0 +1,1253 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(megaco_tcp_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include("megaco_test_lib.hrl").
+
+%% -compile(export_all).
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+
+ start/1,
+ start_normal/1,
+ start_invalid_opt/1,
+ start_and_stop/1,
+
+ sending/1,
+ sendreceive/1,
+ block_unblock/1,
+
+ errors/1,
+ socket_failure/1,
+ accept_process/1,
+ accept_supervisor/1,
+ connection_supervisor/1,
+ tcp_server/1,
+
+ init_per_testcase/2, fin_per_testcase/2,
+
+ t/0, t/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+-export([
+ receive_message/4,
+ process_received_message/4
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+-record(command, {id, desc, cmd}).
+-record(server, {parent, transport_ref, control_pid, handle}).
+-record(client, {parent, transport_ref, control_pid, handle}).
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+%%----------------------------------------------------------------------
+%% Function: t/0
+%% Description: Run all test cases
+%%----------------------------------------------------------------------
+t() -> megaco_test_lib:t(?MODULE).
+
+
+%%----------------------------------------------------------------------
+%% Function: t/1
+%% Description: Run the specified test cases
+%%----------------------------------------------------------------------
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%%======================================================================
+%% Test server callbacks
+%%======================================================================
+%%----------------------------------------------------------------------
+%% Function: init_per_testcase/2
+%% Description:
+%%----------------------------------------------------------------------
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+
+%%----------------------------------------------------------------------
+%% Function: fin_per_testcase/2
+%% Description:
+%%----------------------------------------------------------------------
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+all(suite) ->
+ [
+ start,
+ sending,
+ errors
+ ].
+
+start(suite) ->
+ [
+ start_normal,
+ start_invalid_opt,
+ start_and_stop
+ ].
+
+sending(suite) ->
+ [
+ sendreceive,
+ block_unblock
+ ].
+
+errors(suite) ->
+ [
+ socket_failure,
+ accept_process,
+ accept_supervisor,
+ connection_supervisor,
+ tcp_server
+ ].
+
+
+%% ------------------ start ------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_normal(suite) ->
+ [];
+start_normal(Config) when is_list(Config) ->
+ put(sname, "start_normal"),
+ p("BEGIN TEST-CASE"),
+ Options = [{port, 20000}, {receive_handle, apa}],
+ {ok, Pid} = start_case(Options, ok),
+ megaco_tcp:stop_transport(Pid),
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_invalid_opt(suite) ->
+ [];
+start_invalid_opt(Config) when is_list(Config) ->
+ put(sname, "start_invalid_opt"),
+ p("BEGIN TEST-CASE"),
+ Options = [{port, 20000}, {receivehandle, apa}],
+ ok = start_case(Options, error),
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop(suite) ->
+ [];
+start_and_stop(doc) ->
+ ["This test case sets up a connection and then cloises it. "
+ "No data is sent. "];
+start_and_stop(Config) when is_list(Config) ->
+ put(sname, "start_and_stop"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = start_and_stop_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = start_and_stop_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {listening, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+start_and_stop_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Listen",
+ cmd = fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify listening",
+ cmd = fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await nothing",
+ cmd = fun(State) ->
+ server_await_nothing(State, 6000)
+ end},
+
+ #command{id = 6,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+
+start_and_stop_client_commands(ServerPort, ServerHost) ->
+ Opts = [{port, ServerPort}, {host, ServerHost}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 4,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #command{id = 5,
+ desc = "Await nothing",
+ cmd = fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #command{id = 7,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+%% ------------------ sending ------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sendreceive(suite) ->
+ [];
+sendreceive(Config) when is_list(Config) ->
+ put(sname, "sendreceive"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = sendreceive_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = sendreceive_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {listening, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+sendreceive_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Listen",
+ cmd = fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify listening",
+ cmd = fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await initial message (ping)",
+ cmd = fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Send reply (pong) to initial message",
+ cmd = fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #command{id = 7,
+ desc = "Await nothing before sending a message (hejsan)",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Send message (hejsan)",
+ cmd = fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #command{id = 9,
+ desc = "Await reply (hoppsan) to message",
+ cmd = fun(State) ->
+ server_await_message(State, "hoppsan", 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 11,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ server_disconnect(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+sendreceive_client_commands(ServerPort, ServerHost) ->
+ Opts = [{port, ServerPort}, {host, ServerHost}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 4,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #command{id = 5,
+ desc = "Send initial message (ping)",
+ cmd = fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #command{id = 6,
+ desc = "Await reply (pong) to initial message",
+ cmd = fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #command{id = 7,
+ desc = "Await message (hejsan)",
+ cmd = fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #command{id = 8,
+ desc = "Send reply (hoppsan) to message",
+ cmd = fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #command{id = 9,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #command{id = 11,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 12,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+block_unblock(suite) ->
+ [];
+block_unblock(Config) when is_list(Config) ->
+ put(sname, "block_unblock"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = block_unblock_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = block_unblock_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {listening, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ ok =
+ receive
+ {blocked, Client} ->
+ p("received blocked message from client [~p] => "
+ "send continue to server [~p]~n", [Client, Server]),
+ Server ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, timeout}
+ end,
+
+ await_command_handler_completion([Server, Client], timer:seconds(30)),
+ p("done"),
+ ok.
+
+
+block_unblock_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Listen",
+ cmd = fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify listening",
+ cmd = fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await initial message (ping)",
+ cmd = fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Send reply (pong) to initial message",
+ cmd = fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #command{id = 7,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ server_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 9,
+ desc = "Await nothing before sending a message (hejsan)",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Send message (hejsan)",
+ cmd = fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #command{id = 11,
+ desc = "Await reply (hoppsan) to message",
+ cmd = fun(State) ->
+ server_await_message(State, "hoppsan", 10000)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ server_disconnect(State)
+ end},
+
+ #command{id = 14,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 15,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+block_unblock_client_commands(ServerPort, ServerHost) ->
+ Opts = [{port, ServerPort}, {host, ServerHost}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 4,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #command{id = 5,
+ desc = "Send initial message (ping)",
+ cmd = fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #command{id = 6,
+ desc = "Await reply (pong) to initial message",
+ cmd = fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #command{id = 7,
+ desc = "Await nothing before blocking",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Block",
+ cmd = fun(State) ->
+ client_block(State)
+ end},
+
+ #command{id = 9,
+ desc = "Notify blocked",
+ cmd = fun(State) ->
+ client_notify_blocked(State)
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before unblocking",
+ cmd = fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #command{id = 11,
+ desc = "Unblock",
+ cmd = fun(State) ->
+ client_unblock(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await message (hejsan)",
+ cmd = fun(State) ->
+ client_await_message(State, "hejsan", 100)
+ end},
+
+ #command{id = 13,
+ desc = "Send reply (hoppsan) to message",
+ cmd = fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #command{id = 14,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 15,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #command{id = 16,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 17,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+
+%% ------------------ errors ------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+socket_failure(suite) ->
+ [];
+socket_failure(Config) when is_list(Config) ->
+ put(sname, "socket_failure"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ socket_faulure().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+accept_process(suite) ->
+ [];
+accept_process(Config) when is_list(Config) ->
+ put(sname, "accept_process"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_accept_process().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+accept_supervisor(suite) ->
+ [];
+accept_supervisor(Config) when is_list(Config) ->
+ put(sname, "accept_supervisor"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_accept_supervisor().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+connection_supervisor(suite) ->
+ [];
+connection_supervisor(Config) when is_list(Config) ->
+ put(sname, "connection_supervisor"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_connection_supervisor().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tcp_server(suite) ->
+ [];
+tcp_server(Config) when is_list(Config) ->
+ put(sname, "tcp_server"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_tcp_server().
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+start_case(Options, Expect) ->
+ p("start transport"),
+ case (catch megaco_tcp:start_transport()) of
+ {ok, Pid} ->
+ p("create listen socket"),
+ case (catch megaco_tcp:listen(Pid, Options)) of
+ ok when Expect =:= ok ->
+ p("extected listen result [ok]"),
+ {ok, Pid};
+ ok ->
+ p("unextected listen result [ok] - stop transport"),
+ megaco_tcp:stop_transport(Pid),
+ ?ERROR(unexpected_start_sucesss);
+ {error, _Reason} when Expect =:= error ->
+ p("extected listen result [error] - stop transport"),
+ megaco_tcp:stop_transport(Pid),
+ ok;
+ {error, Reason} ->
+ p("unextected listen result [error] - stop transport"),
+ megaco_tcp:stop_transport(Pid),
+ ?ERROR({unexpected_start_failure, Reason});
+ Error ->
+ p("unextected listen result"),
+ ?ERROR({unexpected_result, Error})
+ end;
+ {error, Reason} ->
+ p("unextected start_transport result"),
+ ?ERROR({failed_starting_transport, Reason})
+ end.
+
+socket_faulure() ->
+ ?SKIP(not_yet_implemented).
+
+failing_accept_process() ->
+ ?SKIP(not_yet_implemented).
+
+failing_accept_supervisor() ->
+ ?SKIP(not_yet_implemented).
+
+failing_connection_supervisor() ->
+ ?SKIP(not_yet_implemented).
+
+failing_tcp_server() ->
+ ?SKIP(not_yet_implemented).
+
+
+%%----------------------------------------------------------------------
+%% Message Callback functions
+%%----------------------------------------------------------------------
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
+ when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
+ Msg = binary_to_list(BinMsg),
+ ReceiveHandle ! {receive_message, {ControlPid, SendHandle, Msg}},
+ ok.
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
+ when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
+ Msg = binary_to_list(BinMsg),
+ ReceiveHandle ! {process_received_message, {ControlPid, SendHandle, Msg}},
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+%% ------- Server command handler and utility functions ----------
+
+server_start_command_handler(Node, Commands) ->
+ start_command_handler(Node, Commands, #server{}, "server").
+
+server_start_transport(State) when is_record(State, server) ->
+ case (catch megaco_tcp:start_transport()) of
+ {ok, Ref} ->
+ {ok, State#server{transport_ref = Ref}};
+ Error ->
+ Error
+ end.
+
+server_listen(#server{transport_ref = Ref} = State, Options)
+ when is_record(State, server) andalso is_list(Options) ->
+ Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
+ case (catch megaco_tcp:listen(Ref, Opts)) of
+ ok ->
+ {ok, State};
+ Error ->
+ Error
+ end.
+
+server_notify_listening(#server{parent = Parent} = State)
+ when is_record(State, server) ->
+ Parent ! {listening, self()},
+ {ok, State}.
+
+server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
+ receive
+ {continue, Parent} ->
+ {ok, State}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_await_initial_message(State, InitialMessage, Timeout)
+ when is_record(State, server) ->
+ receive
+ {receive_message, {ControlPid, Handle, InitialMessage}} ->
+ NewState = State#server{control_pid = ControlPid,
+ handle = Handle},
+ {ok, NewState};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_send_message(#server{handle = Handle} = State, Message) ->
+ megaco_tcp:send_message(Handle, Message),
+ {ok, State}.
+
+server_await_nothing(State, Timeout)
+ when is_record(State, server) ->
+ receive
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {ok, State}
+ end.
+
+
+server_await_message(State, ExpectMessage, Timeout)
+ when is_record(State, server) ->
+ receive
+ {receive_message, {_, _, ExpectMessage}} ->
+ {ok, State};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_disconnect(#server{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:close(Handle),
+ {ok, State#server{handle = undefined}}.
+
+%% server_block(#server{handle = Handle} = State)
+%% when (Handle =/= undefined) ->
+%% megaco_tcp:block(Handle),
+%% {ok, State}.
+
+%% server_unblock(#server{handle = Handle} = State)
+%% when (Handle =/= undefined) ->
+%% megaco_tcp:unblock(Handle),
+%% {ok, State}.
+
+server_stop_transport(#server{transport_ref = Ref} = State)
+ when (Ref =/= undefined) ->
+ megaco_tcp:stop_transport(Ref),
+ {ok, State}.
+
+
+%% ------- Client command handler and utility functions ----------
+
+client_start_command_handler(Node, Commands) ->
+ start_command_handler(Node, Commands, #client{}, "client").
+
+client_start_transport(State) when is_record(State, client) ->
+ case (catch megaco_tcp:start_transport()) of
+ {ok, Ref} ->
+ {ok, State#client{transport_ref = Ref}};
+ Error ->
+ Error
+ end.
+
+client_connect(#client{transport_ref = Ref} = State, Options)
+ when is_record(State, client) andalso is_list(Options) ->
+ Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
+ case (catch megaco_tcp:connect(Ref, Opts)) of
+ {ok, Handle, ControlPid} ->
+ {ok, State#client{control_pid = ControlPid,
+ handle = Handle}};
+ Error ->
+ Error
+ end.
+
+client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
+ receive
+ {continue, Parent} ->
+ {ok, State}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+client_notify_blocked(#client{parent = Parent} = State) ->
+ Parent ! {blocked, self()},
+ {ok, State}.
+
+client_await_nothing(State, Timeout)
+ when is_record(State, client) ->
+ receive
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+ after Timeout ->
+ {ok, State}
+ end.
+
+client_send_message(#client{handle = Handle} = State, Message) ->
+ megaco_tcp:send_message(Handle, Message),
+ {ok, State}.
+
+client_await_message(State, ExpectMessage, Timeout)
+ when is_record(State, client) ->
+ receive
+ {receive_message, {_, _, ExpectMessage}} ->
+ {ok, State};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+client_block(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:block(Handle),
+ {ok, State}.
+
+client_unblock(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:unblock(Handle),
+ {ok, State}.
+
+client_disconnect(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:close(Handle),
+ {ok, State#client{handle = undefined, control_pid = undefined}}.
+
+client_stop_transport(#client{transport_ref = Ref} = State)
+ when (Ref =/= undefined) ->
+ megaco_tcp:stop_transport(Ref),
+ {ok, State}.
+
+
+%% -------- Command handler ---------
+
+start_command_handler(Node, Commands, State, ShortName) ->
+ Fun = fun() ->
+ put(sname, ShortName),
+ process_flag(trap_exit, true),
+ Result = (catch command_handler(Commands, State)),
+ p("command handler terminated with: "
+ "~n Result: ~p", [Result]),
+ exit(Result)
+ end,
+ erlang:spawn_link(Node, Fun).
+
+command_handler([], State) ->
+ p("command_handler -> entry when done with"
+ "~n State: ~p", [State]),
+ {ok, State};
+command_handler([#command{id = Id,
+ desc = Desc,
+ cmd = Cmd}|Commands], State) ->
+ p("command_handler -> entry with"
+ "~n Id: ~p"
+ "~n Desc: ~p", [Id, Desc]),
+ case (catch Cmd(State)) of
+ {ok, NewState} ->
+ p("command_handler -> cmd ~w ok", [Id]),
+ command_handler(Commands, NewState);
+ {error, Reason} ->
+ p("command_handler -> cmd ~w error: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_error, Reason}};
+ {'EXIT', Reason} ->
+ p("command_handler -> cmv ~w exit: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_exit, Reason}};
+ Error ->
+ p("command_handler -> cmd ~w failure: "
+ "~n Error: ~p", [Id, Error]),
+ {error, {cmd_failure, Error}}
+ end.
+
+
+await_command_handler_completion(Pids, Timeout) ->
+ await_command_handler_completion(Pids, [], [], Timeout).
+
+await_command_handler_completion([], [], _Good, _Timeout) ->
+ p("await_command_handler_completion -> entry when done"),
+ ok;
+await_command_handler_completion([], Bad, Good, _Timeout) ->
+ p("await_command_handler_completion -> entry when done with bad result: "
+ "~n Bad: ~p"
+ "~n Good: ~p", [Bad, Good]),
+ ok;
+await_command_handler_completion(Pids, Bad, Good, Timeout) ->
+ p("await_command_handler_completion -> entry when waiting for"
+ "~n Pids: ~p"
+ "~n Bad: ~p"
+ "~n Good: ~p"
+ "~n Timeout: ~p", [Pids, Bad, Good, Timeout]),
+ Begin = ms(),
+ receive
+ {'EXIT', Pid, {ok, FinalState}} ->
+ p("await_command_handler_completion -> "
+ "received ok EXIT signal from ~p", [Pid]),
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ await_command_handler_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ p("await_command_handler_completion -> ~p done", [Pid]),
+ await_command_handler_completion(Pids2,
+ Bad,
+ [{Pid, FinalState}|Good],
+ Timeout - (ms() - Begin))
+ end;
+
+ {'EXIT', Pid, {error, Reason}} ->
+ p("await_command_handler_completion -> "
+ "received error EXIT signal from ~p", [Pid]),
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ await_command_handler_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ p("await_command_handler_completion -> ~p done", [Pid]),
+ await_command_handler_completion(Pids2,
+ [{Pid, Reason}|Bad],
+ Good,
+ Timeout - (ms() - Begin))
+ end
+
+ after Timeout ->
+ p("await_command_handler_completion -> timeout"),
+ exit({timeout, Pids})
+ end.
+
+
+
+%% ------- Misc functions --------
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(sname), F, A).
+
+p(S, F, A) when is_list(S) ->
+ io:format("*** [~s] ~p ~s ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()), self(), S | A]);
+p(_S, F, A) ->
+ io:format("*** [~s] ~p ~s *** "
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()), self(), "undefined" | A]).
+
+
+ms() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).