%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2014-2015. 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% %% %% %% Some gen_tcp-specific tests demonstrating problems that were %% encountered during diameter development but have nothing %% specifically to do with diameter. These can cause testcases in %% other suites to fail. %% -module(diameter_gen_tcp_SUITE). -export([suite/0, all/0]). %% testcases -export([send_long/1, connect/1]). -define(LOOPBACK, {127,0,0,1}). -define(GEN_OPTS, [binary, {active, true}, {ip, ?LOOPBACK}]). %% =========================================================================== suite() -> [{timetrap, {minutes, 2}}]. all() -> [connect, %% Appears to fail only when run first. send_long]. %% =========================================================================== %% send_long/1 %% %% Test that a long message is received. send_long(_) -> {Sock, SendF} = connection(), B = list_to_binary(lists:duplicate(1 bsl 20, $X)), ok = SendF(B), B = recv(Sock, size(B), []). recv(_, 0, Acc) -> list_to_binary(lists:reverse(Acc)); recv(Sock, N, Acc) -> receive {tcp, Sock, Bin} -> recv(Sock, N - size(Bin), [Bin | Acc]); T -> {T, Acc} end. %% connection/0 connection() -> {ok, LSock} = gen_tcp:listen(0, ?GEN_OPTS), {ok, PortNr} = inet:port(LSock), LPid = self(), {Pid, MRef} = spawn_monitor(fun() -> connect(PortNr, LPid) end), {ok, Sock} = gen_tcp:accept(LSock), receive {Pid, F} -> {Sock, F}; {'DOWN', MRef, process, _, _} = T -> T end. %% connect/2 connect(PortNr, LPid) -> {ok, Sock} = gen_tcp:connect(?LOOPBACK, PortNr, ?GEN_OPTS), LPid ! {self(), fun(B) -> send(Sock, B) end}, down(LPid). %% send/2 %% %% Send from a spawned process just to avoid sending from the %% receiving process, in case it's significant. send(Sock, Bin) -> {_, MRef} = spawn_monitor(fun() -> exit(gen_tcp:send(Sock, Bin)) end), down(MRef). %% =========================================================================== %% connect/1 %% %% Test that simultaneous connections succeed. This fails sporadically %% on OS X at the time of writing, when gen_tcp:connect/2 returns %% {error, econnreset}. connect(_) -> {ok, LSock} = gen_tcp:listen(0, ?GEN_OPTS), {ok, {_,PortNr}} = inet:sockname(LSock), Count = lists:seq(1,8), %% 8 simultaneous connects As = [gen_accept(LSock) || _ <- Count], %% Wait for spawned processes to have called gen_tcp:accept/1 %% (presumably). receive after 2000 -> ok end, Cs = [gen_connect(PortNr) || _ <- Count], [] = failures(Cs), [] = failures(As). failures(Monitors) -> [RC || {_, MRef} <- Monitors, RC <- [down(MRef)], ok /= element(1, RC)]. gen_accept(LSock) -> spawn_monitor(fun() -> exit(gen_tcp:accept(LSock)) end). gen_connect(PortNr) -> spawn_monitor(fun() -> exit(gen_tcp:connect(?LOOPBACK, PortNr, ?GEN_OPTS)) end). %% =========================================================================== %% down/1 down(Pid) when is_pid(Pid) -> down(monitor(process, Pid)); down(MRef) -> receive {'DOWN', MRef, process, _, Reason} -> Reason end.