aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/socket_SUITE.erl
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-10-12 15:54:46 +0200
committerMicael Karlberg <[email protected]>2018-10-12 15:54:46 +0200
commit09168a9d0a78319639d62254da717090e21c47ab (patch)
tree2f10025b70c8f6152a961e8a82763a3adbb2cab8 /lib/kernel/test/socket_SUITE.erl
parent22336422d7a014db53dcba7ff1b6e71a1729d89a (diff)
downloadotp-09168a9d0a78319639d62254da717090e21c47ab.tar.gz
otp-09168a9d0a78319639d62254da717090e21c47ab.tar.bz2
otp-09168a9d0a78319639d62254da717090e21c47ab.zip
[socket-nif|test] Add multi accept timeout test case
Added simple multi-accept (multiple acceptors) timeout testcase. OTP-14831
Diffstat (limited to 'lib/kernel/test/socket_SUITE.erl')
-rw-r--r--lib/kernel/test/socket_SUITE.erl436
1 files changed, 436 insertions, 0 deletions
diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl
index de6a20e60b..3f4347c52f 100644
--- a/lib/kernel/test/socket_SUITE.erl
+++ b/lib/kernel/test/socket_SUITE.erl
@@ -47,6 +47,8 @@
api_to_connect_tcp6/1,
api_to_accept_tcp4/1,
api_to_accept_tcp6/1,
+ api_to_maccept_tcp4/1,
+ api_to_maccept_tcp6/1,
api_to_send_tcp4/1,
api_to_send_tcp6/1,
api_to_sendto_udp4/1,
@@ -1570,6 +1572,440 @@ api_to_accept_tcp(InitState) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test the multi accept timeout option
+%% on an IPv4 TCP (stream) socket with multiple acceptor processes
+%% (three in this case).
+api_to_maccept_tcp4(suite) ->
+ [];
+api_to_maccept_tcp4(doc) ->
+ [];
+api_to_maccept_tcp4(_Config) when is_list(_Config) ->
+ tc_try(api_to_maccept_tcp4,
+ fun() ->
+ InitState = #{domain => inet, timeout => 5000},
+ ok = api_to_maccept_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the accept timeout option
+%% on an IPv6 TCP (stream) socket.
+api_to_maccept_tcp6(suite) ->
+ [];
+api_to_maccept_tcp6(doc) ->
+ [];
+api_to_maccept_tcp6(_Config) when is_list(_Config) ->
+ tc_try(api_to_maccept_tcp4,
+ fun() ->
+ not_yet_implemented(),
+ InitState = #{domain => inet6, timeout => 5000},
+ ok = api_to_maccept_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_to_maccept_tcp(InitState) ->
+ PrimAcceptorSeq =
+ [
+ %% *** Init part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ receive
+ {start, Tester} ->
+ MRef = erlang:monitor(process, Tester),
+ {ok, State#{tester => Tester,
+ tester_mref => MRef}}
+ end
+ end},
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LAddr = which_local_addr(Domain),
+ LSA = #{family => Domain, addr => LAddr},
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create (listen) socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+
+ #{desc => "announce ready",
+ cmd => fun(#{lsock := LSock, tester := Tester}) ->
+ ei("announcing port to tester (~p)", [Tester]),
+ Tester ! {ready, self(), LSock},
+ ok
+ end},
+ #{desc => "await continue",
+ cmd => fun(#{tester := Tester} = _State) ->
+ receive
+ {'DOWN', _, process, Tester, Reason} ->
+ {error, {unexpected_exit, tester, Reason}};
+ {continue, Tester} ->
+ ok
+ end
+ end},
+
+ %% *** The actual test part ***
+ #{desc => "attempt to accept (without success)",
+ cmd => fun(#{lsock := LSock, timeout := To} = State) ->
+ Start = t(),
+ case socket:accept(LSock, To) of
+ {error, timeout} ->
+ {ok, State#{start => Start, stop => t()}};
+ {ok, Sock} ->
+ (catch socket:close(Sock)),
+ {error, unexpected_success};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate timeout time",
+ cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) ->
+ TDiff = tdiff(Start, Stop),
+ if
+ (TDiff >= To) ->
+ ok;
+ true ->
+ {error, {unexpected_timeout, TDiff, To}}
+ end
+ end},
+ #{desc => "announce ready",
+ cmd => fun(#{tester := Tester}) ->
+ ei("announcing port to tester (~p)", [Tester]),
+ Tester ! {ready, self()},
+ ok
+ end},
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = _State) ->
+ receive
+ {'DOWN', _, process, Tester, Reason} ->
+ {error, {unexpected_exit, tester, Reason}};
+ {terminate, Tester} ->
+ ok
+ end
+ end},
+
+ %% *** Close (listen) socket ***
+ #{desc => "close (listen) socket",
+ cmd => fun(#{lsock := LSock} = State) ->
+ sock_close(LSock),
+ {ok, maps:remove(sock3, State)}
+ end},
+
+ %% *** We are done ***
+ #{desc => "finish",
+ cmd => fun(_) ->
+ {ok, normal}
+ end}
+ ],
+
+
+ SecAcceptorSeq =
+ [
+ %% *** Init part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ receive
+ {start, Tester, LSock} ->
+ MRef = erlang:monitor(process, Tester),
+ {ok, State#{tester => Tester,
+ lsock => LSock,
+ tester_mref => MRef}}
+ end
+ end},
+ #{desc => "announce ready (1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ Tester ! {ready, self()},
+ ok
+ end},
+ #{desc => "await continue",
+ cmd => fun(#{tester := Tester} = _State) ->
+ receive
+ {'DOWN', _, process, Tester, Reason} ->
+ ee("Unexpected DOWN regarding tester ~p: "
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, tester, Reason}};
+ {continue, Tester} ->
+ ok
+ end
+ end},
+
+ %% *** The actual test part ***
+ #{desc => "attempt to accept (without success)",
+ cmd => fun(#{lsock := LSock, timeout := To} = State) ->
+ Start = t(),
+ case socket:accept(LSock, To) of
+ {error, timeout} ->
+ {ok, State#{start => Start, stop => t()}};
+ {ok, Sock} ->
+ (catch socket:close(Sock)),
+ {error, unexpected_success};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate timeout time",
+ cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) ->
+ TDiff = tdiff(Start, Stop),
+ if
+ (TDiff >= To) ->
+ ok;
+ true ->
+ {error, {unexpected_timeout, TDiff, To}}
+ end
+ end},
+ #{desc => "announce ready (2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ Tester ! {ready, self()},
+ ok
+ end},
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = _State) ->
+ receive
+ {'DOWN', _, process, Tester, Reason} ->
+ ee("Unexpected DOWN regarding tester ~p: "
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, tester, Reason}};
+ {terminate, Tester} ->
+ ok
+ end
+ end},
+
+ %% *** We are done ***
+ #{desc => "finish",
+ cmd => fun(_) ->
+ {ok, normal}
+ end}
+ ],
+
+
+ TesterSeq =
+ [
+ %% Init part
+ #{desc => "monitor prim-acceptor",
+ cmd => fun(#{prim_acceptor := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor sec-acceptor 1",
+ cmd => fun(#{sec_acceptor1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor sec-acceptor 2",
+ cmd => fun(#{sec_acceptor2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+
+ %% Start the prim-acceptor
+ #{desc => "start prim-acceptor",
+ cmd => fun(#{prim_acceptor := Pid} = _State) ->
+ Pid ! {start, self()},
+ ok
+ end},
+ #{desc => "await prim-acceptor ready (1)",
+ cmd => fun(#{prim_acceptor := Pid} = State) ->
+ receive
+ {'DOWN', _, process, Pid, Reason} ->
+ ee("Unexpected DOWN regarding prim-acceptor ~p:"
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, prim_acceptor}};
+ {ready, Pid, LSock} ->
+ {ok, State#{lsock => LSock}}
+ end
+ end},
+
+ %% Start sec-acceptor-1
+ #{desc => "start sec-acceptor 1",
+ cmd => fun(#{sec_acceptor1 := Pid, lsock := LSock} = _State) ->
+ Pid ! {start, self(), LSock},
+ ok
+ end},
+ #{desc => "await sec-acceptor 1 ready (1)",
+ cmd => fun(#{sec_acceptor1 := Pid} = _State) ->
+ receive
+ {'DOWN', _, process, Pid, Reason} ->
+ ee("Unexpected DOWN regarding sec-acceptor 1 ~p:"
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, sec_acceptor_1}};
+ {ready, Pid} ->
+ ok
+ end
+ end},
+
+ %% Start sec-acceptor-2
+ #{desc => "start sec-acceptor 2",
+ cmd => fun(#{sec_acceptor2 := Pid, lsock := LSock} = _State) ->
+ Pid ! {start, self(), LSock},
+ ok
+ end},
+ #{desc => "await sec-acceptor 2 ready (1)",
+ cmd => fun(#{sec_acceptor2 := Pid} = _State) ->
+ receive
+ {'DOWN', _, process, Pid, Reason} ->
+ ee("Unexpected DOWN regarding sec-acceptor 2 ~p:"
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, sec_acceptor_2}};
+ {ready, Pid} ->
+ ok
+ end
+ end},
+
+ %% Activate the acceptor(s)
+ #{desc => "active prim-acceptor",
+ cmd => fun(#{prim_acceptor := Pid} = _State) ->
+ Pid ! {continue, self()},
+ ok
+ end},
+ #{desc => "active sec-acceptor 1",
+ cmd => fun(#{sec_acceptor1 := Pid} = _State) ->
+ Pid ! {continue, self()},
+ ok
+ end},
+ #{desc => "active sec-acceptor 2",
+ cmd => fun(#{sec_acceptor2 := Pid} = _State) ->
+ Pid ! {continue, self()},
+ ok
+ end},
+
+ %% Await acceptor(s) completions
+ #{desc => "await prim-acceptor ready (2)",
+ cmd => fun(#{prim_acceptor := Pid} = _State) ->
+ receive
+ {'DOWN', _, process, Pid, Reason} ->
+ ee("Unexpected DOWN regarding prim-acceptor ~p:"
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, prim_acceptor}};
+ {ready, Pid} ->
+ ok
+ end
+ end},
+ #{desc => "await sec-acceptor 1 ready (2)",
+ cmd => fun(#{sec_acceptor1 := Pid} = _State) ->
+ receive
+ {'DOWN', _, process, Pid, Reason} ->
+ ee("Unexpected DOWN regarding sec-acceptor 1 ~p:"
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, sec_acceptor_1}};
+ {ready, Pid} ->
+ ok
+ end
+ end},
+ #{desc => "await sec-acceptor 2 ready (2)",
+ cmd => fun(#{sec_acceptor2 := Pid} = _State) ->
+ receive
+ {'DOWN', _, process, Pid, Reason} ->
+ ee("Unexpected DOWN regarding sec-acceptor 2 ~p:"
+ "~n ~p", [Reason]),
+ {error, {unexpected_exit, sec_acceptor_2}};
+ {ready, Pid} ->
+ ok
+ end
+ end},
+
+
+ %% Terminate the acceptor(s)
+ #{desc => "order prim-acceptor to terminate",
+ cmd => fun(#{prim_acceptor := Pid} = _State) ->
+ ei("send terminate command to prim-acceptor (~p)", [Pid]),
+ Pid ! {terminate, self()},
+ ok
+ end},
+ #{desc => "order sec-acceptor 1 to terminate",
+ cmd => fun(#{sec_acceptor1 := Pid} = _State) ->
+ ei("send terminate command to sec-acceptor-1 (~p)", [Pid]),
+ Pid ! {terminate, self()},
+ ok
+ end},
+ #{desc => "order sec-acceptor 2 to terminate",
+ cmd => fun(#{sec_acceptor2 := Pid} = _State) ->
+ ei("send terminate command to sec-acceptor-2 (~p)", [Pid]),
+ Pid ! {terminate, self()},
+ ok
+ end},
+
+ %% Await acceptor(s) termination
+ #{desc => "await prim-acceptor termination",
+ cmd => fun(#{prim_acceptor := Pid} = State) ->
+ receive
+ {'DOWN', _, process, Pid, _} ->
+ State1 = maps:remove(prim_acceptor, State),
+ {ok, State1}
+ end
+ end},
+ #{desc => "await sec-acceptor 1 termination",
+ cmd => fun(#{sec_acceptor1 := Pid} = State) ->
+ receive
+ {'DOWN', _, process, Pid, _} ->
+ State1 = maps:remove(sec_acceptor1, State),
+ {ok, State1}
+ end
+ end},
+ #{desc => "await sec-acceptor 2 termination",
+ cmd => fun(#{sec_acceptor2 := Pid} = State) ->
+ receive
+ {'DOWN', _, process, Pid, _} ->
+ State1 = maps:remove(sec_acceptor2, State),
+ {ok, State1}
+ end
+ end},
+
+ %% *** We are done ***
+ #{desc => "finish",
+ cmd => fun(_) ->
+ {ok, normal}
+ end}
+ ],
+
+ p("create prim-acceptor evaluator"),
+ PrimAInitState = InitState,
+ PrimAcceptor = evaluator_start("prim-acceptor",
+ PrimAcceptorSeq, PrimAInitState),
+
+ p("create prim-acceptor 1 evaluator"),
+ SecAInitState1 = maps:remove(domain, InitState),
+ SecAcceptor1 = evaluator_start("sec-acceptor-1",
+ SecAcceptorSeq, SecAInitState1),
+
+ p("create prim-acceptor 2 evaluator"),
+ SecAInitState2 = SecAInitState1,
+ SecAcceptor2 = evaluator_start("sec-acceptor-2",
+ SecAcceptorSeq, SecAInitState2),
+
+ p("create tester evaluator"),
+ TesterInitState = #{prim_acceptor => PrimAcceptor,
+ sec_acceptor1 => SecAcceptor1,
+ sec_acceptor2 => SecAcceptor2},
+ Tester = evaluator_start("tester", TesterSeq, TesterInitState),
+
+ p("await evaluator(s)"),
+ ok = await_evaluator_finish([PrimAcceptor, SecAcceptor1, SecAcceptor2, Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%% This test case is intended to test the send timeout option
%% on an IPv4 TCP (stream) socket.
api_to_send_tcp4(suite) ->