diff options
Diffstat (limited to 'erts/emulator/test/esock-ttest')
-rwxr-xr-x | erts/emulator/test/esock-ttest | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/erts/emulator/test/esock-ttest b/erts/emulator/test/esock-ttest new file mode 100755 index 0000000000..418b19eec1 --- /dev/null +++ b/erts/emulator/test/esock-ttest @@ -0,0 +1,350 @@ +#!/usr/bin/env escript + +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% ========================================================================== +%% +%% This is a simple wrapper escript on top of the socket ttest program(s). +%% The idea is to make it simple to run in a normal shell (bash). +%% +%% ========================================================================== + +-define(SECS(I), timer:seconds(I)). + +-define(CLIENT_MSG_1_MAX_OUTSTANDING, 100). +-define(CLIENT_MSG_2_MAX_OUTSTANDING, 10). +-define(CLIENT_MSG_3_MAX_OUTSTANDING, 1). + +main(Args) -> + State = process_args(Args), + exec(State), + ok. + +usage(ErrorString) when is_list(ErrorString) -> + eprint(ErrorString), + usage(), + erlang:halt(0). + +usage() -> + io:format("usage: ~s [options]" + "~n" + "~n This erlang script is used to start the (e)socket ttest " + "~n units (server or client)." + "~n" + "~n options: " + "~n --help Display this info and exit. " + "~n --server [server-options] Start a server. " + "~n There are no mandatory server options." + "~n --client client-options Start a client" + "~n Some client options are mandatory and" + "~n others optional." + "~n --active <active> boolean() | once." + "~n Valid for both client and server." + "~n Defaults to: false" + "~n --transport <transport> Which transport to use: gen|sock[:plain|msg]" + "~n gen: gen_tcp" + "~n sock: socket" + "~n plain: recv/send (default)" + "~n msg: recvmsg/sendmsg" + "~n Defaults to: sock:plain" + "~n --scon <addr>:<port> Address and port of the server." + "~n The address part is in the standard form:" + "~n \"a.b.c.d\"." + "~n Only valid for client." + "~n Mandatory." + "~n --msg-id <1|2|3> Choose which message to use during the test." + "~n Basically: " + "~n 1: small" + "~n 2: medium" + "~n 3: large" + "~n Defaults to: 1" + "~n --max-outstanding <Num> How many messages to send before waiting for" + "~n a reply." + "~n Valid only for client." + "~n Defaults to: " + "~n MsgID 1: 100" + "~n MsgID 2: 10" + "~n MsgID 3: 1" + "~n --runtime <Time> Time of the test in seconds." + "~n Only valid for client." + "~n Mandatory." + "~n Defaults to: 60 (seconds)" + "~n" + "~n" + "~n", + [scriptname()]), + ok. + +process_args(["--help"|_]) -> + usage(); +process_args(["--server"|ServerArgs]) -> + process_server_args(ServerArgs); +process_args(["--client"|ClientArgs]) -> + process_client_args(ClientArgs); +process_args(Args) -> + usage(f("Invalid Args: " + "~n ~p", [Args])). + + +process_server_args(Args) -> + Defaults = #{role => server, + active => false, + transport => {sock, plain}}, + process_server_args(Args, Defaults). + +process_server_args([], State) -> + State; + +process_server_args(["--active", Active|Args], State) + when ((Active =:= "false") orelse + (Active =:= "once") orelse + (Active =:= "true")) -> + process_server_args(Args, State#{active => list_to_atom(Active)}); + +process_server_args(["--transport", "gen" | Args], State) -> + process_server_args(Args, State#{transport => gen}); +process_server_args(["--transport", "sock" | Args], State) -> + process_server_args(Args, State#{transport => {sock, plain}}); +process_server_args(["--transport", "sock:plain" | Args], State) -> + process_server_args(Args, State#{transport => {sock, plain}}); +process_server_args(["--transport", "sock:msg" | Args], State) -> + process_server_args(Args, State#{transport => {sock, msg}}); + +process_server_args([Arg|_], _State) -> + usage(f("Invalid Server arg: ~s", [Arg])). + + +process_client_args(Args) -> + Defaults = #{role => client, + active => false, + transport => {sock, plain}, + %% Will cause error if not provided + %% Should be "addr:port" + server => undefined, + msg_id => 1, + %% Will be filled in based on msg_id if not provided + max_outstanding => undefined, + runtime => ?SECS(60)}, + process_client_args(Args, Defaults). + +process_client_args([], State) -> + process_client_args_ensure_max_outstanding(State); + +process_client_args(["--active", Active|Args], State) + when ((Active =:= "false") orelse + (Active =:= "once") orelse + (Active =:= "true")) -> + process_client_args(Args, State#{active => list_to_atom(Active)}); + +process_client_args(["--transport", "gen" | Args], State) -> + process_client_args(Args, State#{transport => gen}); +process_client_args(["--transport", "sock" | Args], State) -> + process_client_args(Args, State#{transport => {sock, plain}}); +process_client_args(["--transport", "sock:plain" | Args], State) -> + process_client_args(Args, State#{transport => {sock, plain}}); +process_client_args(["--transport", "sock:msg" | Args], State) -> + process_client_args(Args, State#{transport => {sock, msg}}); + +process_client_args(["--msg-id", MsgID|Args], State) + when ((MsgID =:= "1") orelse + (MsgID =:= "2") orelse + (MsgID =:= "3")) -> + process_client_args(Args, State#{msg_id => list_to_integer(MsgID)}); + +process_client_args(["--max-outstanding", Max|Args], State) -> + try list_to_integer(Max) of + I when (I > 0) -> + process_client_args(Args, State#{max_outstanding => I}); + _ -> + usage(f("Invalid Max Outstanding: ~s", [Max])) + catch + _:_:_ -> + usage(f("Invalid Max Outstanding: ~s", [Max])) + end; + +process_client_args(["--scon", Server|Args], State) -> + case string:tokens(Server, [$:]) of + [AddrStr,PortStr] -> + Addr = case inet:parse_address(AddrStr) of + {ok, A} -> + A; + {error, _} -> + usage(f("Invalid Server Address: ~s", [AddrStr])) + end, + Port = try list_to_integer(PortStr) of + I when (I > 0) -> + I; + _ -> + usage(f("Invalid Server Port: ~s", [PortStr])) + catch + _:_:_ -> + usage(f("Invalid Server Port: ~s", [PortStr])) + end, + process_client_args(Args, State#{server => {Addr, Port}}); + _ -> + usage(f("Invalid Server: ~s", [Server])) + end; + +process_client_args(["--runtime", T|Args], State) -> + try list_to_integer(T) of + I when (I > 0) -> + process_client_args(Args, State#{runtime => ?SECS(I)}); + _ -> + usage(f("Invalid Run Time: ~s", [T])) + catch + _:_:_ -> + usage(f("Invalid Run Time: ~s", [T])) + end; + +process_client_args([Arg|_], _State) -> + usage(f("Invalid Client arg: ~s", [Arg])). + + +process_client_args_ensure_max_outstanding( + #{msg_id := 1, + max_outstanding := undefined} = State) -> + State#{max_outstanding => ?CLIENT_MSG_1_MAX_OUTSTANDING}; +process_client_args_ensure_max_outstanding( + #{msg_id := 2, + max_outstanding := undefined} = State) -> + State#{max_outstanding => ?CLIENT_MSG_2_MAX_OUTSTANDING}; +process_client_args_ensure_max_outstanding( + #{msg_id := 3, + max_outstanding := undefined} = State) -> + State#{max_outstanding => ?CLIENT_MSG_3_MAX_OUTSTANDING}; +process_client_args_ensure_max_outstanding( + #{msg_id := MsgID, + max_outstanding := MaxOutstanding} = State) + when ((MsgID =:= 1) orelse + (MsgID =:= 2) orelse + (MsgID =:= 3)) andalso + (is_integer(MaxOutstanding) andalso (MaxOutstanding > 0)) -> + State; +process_client_args_ensure_max_outstanding( + #{msg_id := MsgID, + max_outstanding := MaxOutstanding}) -> + usage(f("Invalid Msg ID (~w) and Max Outstanding (~w)", + [MsgID, MaxOutstanding])). + + + +%% ========================================================================== + +exec(#{role := server, + active := Active, + transport := gen}) -> + case socket_test_ttest_tcp_server_gen:start(Active) of + {ok, {Pid, _}} -> + MRef = erlang:monitor(process, Pid), + receive + {'DOWN', MRef, process, Pid, Info} -> + Info + end; + {error, Reason} -> + eprint(f("Failed starting server: " + "~n ~p", [Reason])), + error + end; +exec(#{role := server, + active := Active, + transport := {sock, Method}}) -> + case socket_test_ttest_tcp_server_socket:start(Method, Active) of + {ok, {Pid, _}} -> + MRef = erlang:monitor(process, Pid), + receive + {'DOWN', MRef, process, Pid, Info} -> + Info + end; + {error, Reason} -> + eprint(f("Failed starting server: " + "~n ~p", [Reason])), + error + end; + +exec(#{role := client, + server := undefined}) -> + usage("Mandatory option 'server' not provided"); +exec(#{role := client, + server := {Addr, Port}, + active := Active, + transport := gen, + msg_id := MsgID, + max_outstanding := MaxOutstanding, + runtime := RunTime}) -> + case socket_test_ttest_tcp_client_gen:start(Active, + Addr, Port, + MsgID, MaxOutstanding, + RunTime) of + {ok, Pid} -> + MRef = erlang:monitor(process, Pid), + receive + {'DOWN', MRef, process, Pid, Info} -> + Info + end; + {error, Reason} -> + eprint(f("Failed starting server: " + "~n ~p", [Reason])), + error + end; +exec(#{role := client, + server := {Addr, Port}, + active := Active, + transport := {sock, Method}, + msg_id := MsgID, + max_outstanding := MaxOutstanding, + runtime := RunTime}) -> + case socket_test_ttest_tcp_client_socket:start(Method, + Active, + Addr, Port, + MsgID, MaxOutstanding, + RunTime) of + {ok, Pid} -> + MRef = erlang:monitor(process, Pid), + receive + {'DOWN', MRef, process, Pid, Info} -> + Info + end; + {error, Reason} -> + eprint(f("Failed starting server: " + "~n ~p", [Reason])), + error + end; +exec(_) -> + usage("Unexpected option combo"), + ok. + + + +%% ========================================================================== + +f(F, A) -> + socket_test_ttest_lib:format(F, A). + +eprint(ErrorString) when is_list(ErrorString) -> + print("<ERROR> " ++ ErrorString ++ "~n", []). + +print(F, A) -> + io:format(F ++ "~n", A). + +scriptname() -> + FullName = escript:script_name(), + filename:basename(FullName). + |