1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2014-2017. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22%% Some gen_tcp-specific tests demonstrating problems that were 23%% encountered during diameter development but have nothing 24%% specifically to do with diameter. These can cause testcases in 25%% other suites to fail. 26%% 27 28-module(diameter_gen_tcp_SUITE). 29 30-export([suite/0, 31 all/0]). 32 33%% testcases 34-export([send_long/1, 35 connect/1]). 36 37-define(LOOPBACK, {127,0,0,1}). 38-define(GEN_OPTS, [binary, {active, true}, {ip, ?LOOPBACK}]). 39 40%% =========================================================================== 41 42suite() -> 43 [{timetrap, {seconds, 10}}]. 44 45all() -> 46 [connect, %% Appears to fail only when run first. 47 send_long]. 48 49%% =========================================================================== 50 51%% send_long/1 52%% 53%% Test that a long message is received. 54 55send_long(_) -> 56 {Sock, SendF} = connection(), 57 B = binary:copy(<<$X>>, 1 bsl 20), 58 ok = SendF(B), 59 B = recv(Sock, size(B), []). 60 61recv(_, 0, Acc) -> 62 list_to_binary(lists:reverse(Acc)); 63recv(Sock, N, Acc) -> 64 receive 65 {tcp, Sock, Bin} -> 66 recv(Sock, N - size(Bin), [Bin | Acc]); 67 T -> 68 {T, Acc} 69 end. 70 71%% connection/0 72 73connection() -> 74 {ok, LSock} = gen_tcp:listen(0, ?GEN_OPTS), 75 {ok, PortNr} = inet:port(LSock), 76 LPid = self(), 77 {Pid, MRef} = spawn_monitor(fun() -> connect(PortNr, LPid) end), 78 {ok, Sock} = gen_tcp:accept(LSock), 79 receive 80 {Pid, F} -> 81 {Sock, F}; 82 {'DOWN', MRef, process, _, _} = T -> 83 T 84 end. 85 86%% connect/2 87 88connect(PortNr, LPid) -> 89 {ok, Sock} = gen_tcp:connect(?LOOPBACK, PortNr, ?GEN_OPTS), 90 LPid ! {self(), fun(B) -> send(Sock, B) end}, 91 down(LPid). 92 93%% send/2 94%% 95%% Send from a spawned process just to avoid sending from the 96%% receiving process, in case it's significant. 97 98send(Sock, Bin) -> 99 {_, MRef} = spawn_monitor(fun() -> exit(gen_tcp:send(Sock, Bin)) end), 100 down(MRef). 101 102%% =========================================================================== 103 104%% connect/1 105%% 106%% Test that simultaneous connections succeed. This fails sporadically 107%% on OS X at the time of writing, when gen_tcp:connect/2 returns 108%% {error, econnreset}. 109 110connect(_) -> 111 {ok, LSock} = gen_tcp:listen(0, ?GEN_OPTS), 112 {ok, {_,PortNr}} = inet:sockname(LSock), 113 Count = lists:seq(1,8), %% 8 simultaneous connects 114 As = [gen_accept(LSock) || _ <- Count], 115 %% Wait for spawned processes to have called gen_tcp:accept/1 116 %% (presumably). 117 receive after 2000 -> ok end, 118 Cs = [gen_connect(PortNr) || _ <- Count], 119 [] = failures(Cs), 120 [] = failures(As). 121 122failures(Monitors) -> 123 [RC || {_, MRef} <- Monitors, RC <- [down(MRef)], ok /= element(1, RC)]. 124 125gen_accept(LSock) -> 126 spawn_monitor(fun() -> 127 exit(gen_tcp:accept(LSock)) 128 end). 129 130gen_connect(PortNr) -> 131 spawn_monitor(fun() -> 132 exit(gen_tcp:connect(?LOOPBACK, PortNr, ?GEN_OPTS)) 133 end). 134 135%% =========================================================================== 136 137%% down/1 138 139down(Pid) 140 when is_pid(Pid) -> 141 down(monitor(process, Pid)); 142 143down(MRef) -> 144 receive {'DOWN', MRef, process, _, Reason} -> Reason end. 145