aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/gen_tcp_api_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/gen_tcp_api_SUITE.erl')
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl219
1 files changed, 219 insertions, 0 deletions
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
new file mode 100644
index 0000000000..11d19aaa82
--- /dev/null
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -0,0 +1,219 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-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%
+%%
+-module(gen_tcp_api_SUITE).
+
+%% Tests the documented API for the gen_tcp functions. The "normal" cases
+%% are not tested here, because they are tested indirectly in this and
+%% and other test suites.
+
+-include("test_server.hrl").
+-include_lib("kernel/include/inet.hrl").
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2,
+ t_accept/1, t_connect_timeout/1, t_accept_timeout/1,
+ t_connect/1, t_connect_bad/1,
+ t_recv/1, t_recv_timeout/1, t_recv_eof/1,
+ t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1,
+ t_fdopen/1]).
+
+all(suite) -> [t_accept, t_connect, t_recv, t_shutdown_write,
+ t_shutdown_both, t_shutdown_error, t_fdopen].
+
+init_per_testcase(_Func, Config) ->
+ Dog = test_server:timetrap(test_server:seconds(60)),
+ [{watchdog, Dog}|Config].
+fin_per_testcase(_Func, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog).
+
+%%% gen_tcp:accept/1,2
+
+t_accept(suite) -> [t_accept_timeout].
+
+t_accept_timeout(doc) -> "Test that gen_tcp:accept/2 (with timeout) works.";
+t_accept_timeout(suite) -> [];
+t_accept_timeout(Config) when is_list(Config) ->
+ ?line {ok, L} = gen_tcp:listen(0, []),
+ ?line timeout({gen_tcp, accept, [L, 200]}, 0.2, 1.0).
+
+%%% gen_tcp:connect/X
+
+t_connect(suite) -> [t_connect_timeout, t_connect_bad].
+
+t_connect_timeout(doc) -> "Test that gen_tcp:connect/4 (with timeout) works.";
+t_connect_timeout(Config) when is_list(Config) ->
+ %%?line BadAddr = {134,138,177,16},
+ %%?line TcpPort = 80,
+ ?line {ok, BadAddr} = unused_ip(),
+ ?line TcpPort = 45638,
+ ?line ok = io:format("Connecting to ~p, port ~p", [BadAddr, TcpPort]),
+ ?line connect_timeout({gen_tcp,connect,[BadAddr,TcpPort,[],200]}, 0.2, 5.0).
+
+t_connect_bad(doc) ->
+ ["Test that gen_tcp:connect/3 handles non-existings hosts, and other ",
+ "invalid things."];
+t_connect_bad(suite) -> [];
+t_connect_bad(Config) when is_list(Config) ->
+ ?line NonExistingPort = 45638, % Not in use, I hope.
+ ?line {error, Reason1} = gen_tcp:connect(localhost, NonExistingPort, []),
+ ?line io:format("Error for connection attempt to port not in use: ~p",
+ [Reason1]),
+
+ ?line {error, Reason2} = gen_tcp:connect("non-existing-host-xxx", 7, []),
+ ?line io:format("Error for connection attempt to non-existing host: ~p",
+ [Reason2]),
+ ok.
+
+
+%%% gen_tcp:recv/X
+
+t_recv(suite) -> [t_recv_timeout, t_recv_eof].
+
+t_recv_timeout(doc) -> "Test that gen_tcp:recv/3 (with timeout works).";
+t_recv_timeout(suite) -> [];
+t_recv_timeout(Config) when is_list(Config) ->
+ ?line {ok, L} = gen_tcp:listen(0, []),
+ ?line {ok, Port} = inet:port(L),
+ ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ ?line {ok, _A} = gen_tcp:accept(L),
+ ?line timeout({gen_tcp, recv, [Client, 0, 200]}, 0.2, 5.0).
+
+t_recv_eof(doc) -> "Test that end of file on a socket is reported correctly.";
+t_recv_eof(suite) -> [];
+t_recv_eof(Config) when is_list(Config) ->
+ ?line {ok, L} = gen_tcp:listen(0, []),
+ ?line {ok, Port} = inet:port(L),
+ ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ ?line {ok, A} = gen_tcp:accept(L),
+ ?line ok = gen_tcp:close(A),
+ ?line {error, closed} = gen_tcp:recv(Client, 0),
+ ok.
+
+%%% gen_tcp:shutdown/2
+
+t_shutdown_write(Config) when is_list(Config) ->
+ ?line {ok, L} = gen_tcp:listen(0, []),
+ ?line {ok, Port} = inet:port(L),
+ ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ ?line {ok, A} = gen_tcp:accept(L),
+ ?line ok = gen_tcp:shutdown(A, write),
+ ?line {error, closed} = gen_tcp:recv(Client, 0),
+ ok.
+
+t_shutdown_both(Config) when is_list(Config) ->
+ ?line {ok, L} = gen_tcp:listen(0, []),
+ ?line {ok, Port} = inet:port(L),
+ ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ ?line {ok, A} = gen_tcp:accept(L),
+ ?line ok = gen_tcp:shutdown(A, read_write),
+ ?line {error, closed} = gen_tcp:recv(Client, 0),
+ ok.
+
+t_shutdown_error(Config) when is_list(Config) ->
+ ?line {ok, L} = gen_tcp:listen(0, []),
+ ?line {error, enotconn} = gen_tcp:shutdown(L, read_write),
+ ?line ok = gen_tcp:close(L),
+ ?line {error, closed} = gen_tcp:shutdown(L, read_write),
+ ok.
+
+
+%%% gen_tcp:fdopen/2
+
+t_fdopen(Config) when is_list(Config) ->
+ ?line Question = "Aaaa... Long time ago in a small town in Germany,",
+ ?line Answer = "there was a shoemaker, Schumacher was his name.",
+ ?line {ok, L} = gen_tcp:listen(0, [{active, false}]),
+ ?line {ok, Port} = inet:port(L),
+ ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ ?line {ok, A} = gen_tcp:accept(L),
+ ?line {ok, FD} = prim_inet:getfd(A),
+ ?line {ok, Server} = gen_tcp:fdopen(FD, []),
+ ?line ok = gen_tcp:send(Client, Question),
+ ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000),
+ ?line ok = gen_tcp:send(Server, Answer),
+ ?line {ok, Answer} = gen_tcp:recv(Client, length(Answer), 2000),
+ ?line ok = gen_tcp:close(Client),
+ ?line {error,closed} = gen_tcp:recv(A, 1, 2000),
+ ?line ok = gen_tcp:close(Server),
+ ?line ok = gen_tcp:close(A),
+ ?line ok = gen_tcp:close(L),
+ ok.
+
+
+
+%%% Utilities
+
+%% Calls M:F/length(A), which should return a timeout error, and complete
+%% within the given time.
+
+timeout({M,F,A}, Lower, Upper) ->
+ case test_server:timecall(M, F, A) of
+ {Time, Result} when Time < Lower ->
+ test_server:fail({too_short_time, Time, Result});
+ {Time, Result} when Time > Upper ->
+ test_server:fail({too_long_time, Time, Result});
+ {_, {error, timeout}} ->
+ ok;
+ {_, Result} ->
+ test_server:fail({unexpected_result, Result})
+ end.
+
+connect_timeout({M,F,A}, Lower, Upper) ->
+ case test_server:timecall(M, F, A) of
+ {Time, Result} when Time < Lower ->
+ case Result of
+ {error,econnrefused=E} ->
+ {comment,"Not tested -- got error "++atom_to_list(E)};
+ {error,enetunreach=E} ->
+ {comment,"Not tested -- got error "++atom_to_list(E)};
+ {ok,Socket} -> % What the...
+ Pinfo = erlang:port_info(Socket),
+ Db = inet_db:lookup_socket(Socket),
+ Peer = inet:peername(Socket),
+ test_server:fail({too_short_time, Time,
+ [Result,Pinfo,Db,Peer]});
+ _ ->
+ test_server:fail({too_short_time, Time, Result})
+ end;
+ {Time, Result} when Time > Upper ->
+ test_server:fail({too_long_time, Time, Result});
+ {_, {error, timeout}} ->
+ ok;
+ {_, Result} ->
+ test_server:fail({unexpected_result, Result})
+ end.
+
+%% Try to obtain an unused IP address in the local network.
+
+unused_ip() ->
+ ?line {ok, Host} = inet:gethostname(),
+ ?line {ok, Hent} = inet:gethostbyname(Host),
+ ?line #hostent{h_addr_list=[{A, B, C, _D}|_]} = Hent,
+ %% Note: In our net, addresses below 16 are reserved for routers and
+ %% other strange creatures.
+ ?line IP = unused_ip(A, B, C, 16),
+ io:format("we = ~p, unused_ip = ~p~n", [Hent, IP]),
+ IP.
+
+unused_ip(_, _, _, 255) -> error;
+unused_ip(A, B, C, D) ->
+ case inet:gethostbyaddr({A, B, C, D}) of
+ {ok, _} -> unused_ip(A, B, C, D+1);
+ {error, _} -> {ok, {A, B, C, D}}
+ end.