From 02bc08db9e8d4254a5916d0a798a89471923f294 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 26 Feb 2019 11:09:07 +0100 Subject: [net|test] Add "proper" test suite Add a (basically) placeholder test suite for the net module. OTP-15635 --- erts/emulator/test/Makefile | 6 + erts/emulator/test/net_SUITE.erl | 475 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 erts/emulator/test/net_SUITE.erl diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index c2a01b9e71..9e9cc2ead8 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -46,6 +46,9 @@ SOCKET_MODULES = \ socket_test_ttest_tcp_server_socket \ socket_SUITE +NET_MODULES = \ + net_SUITE + MODULES= \ a_SUITE \ after_SUITE \ @@ -102,6 +105,7 @@ MODULES= \ monitor_SUITE \ multi_load_SUITE \ nested_SUITE \ + $(NET_MODULES) \ nif_SUITE \ node_container_SUITE \ nofrag_SUITE \ @@ -178,6 +182,7 @@ HRL_FILES= \ socket_test_ttest_client.hrl TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +NET_TARGETS = $(NET_MODULES:%=$(EBIN)/%.$(EMULATOR)) SOCKET_TARGETS = $(SOCKET_MODULES:%=$(EBIN)/%.$(EMULATOR)) EMAKEFILE=Emakefile @@ -227,6 +232,7 @@ docs: targets: $(TARGET_FILES) socket_targets: $(SOCKET_TARGETS) +net_targets: $(NET_TARGETS) # ---------------------------------------------------- # Special targets diff --git a/erts/emulator/test/net_SUITE.erl b/erts/emulator/test/net_SUITE.erl new file mode 100644 index 0000000000..cd95ad3903 --- /dev/null +++ b/erts/emulator/test/net_SUITE.erl @@ -0,0 +1,475 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2019-2019. 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 test suite is basically a "placeholder" for a proper test suite... +%% + +%% Run the entire test suite: +%% ts:run(emulator, net_SUITE, [batch]). +%% +%% Run a specific group: +%% ts:run(emulator, net_SUITE, {group, foo}, [batch]). +%% +%% Run a specific test case: +%% ts:run(emulator, net_SUITE, foo, [batch]). + +-module(net_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +%% Suite exports +-export([suite/0, all/0, groups/0]). +-export([init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([ + %% *** API Basic *** + api_b_gethostname/1, + api_b_name_and_addr_info/1, + + api_b_name_and_index/1 + + %% Tickets + ]). + + +%% -include("socket_test_evaluator.hrl"). + +%% Internal exports +%% -export([]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(SLEEP(T), receive after T -> ok end). + +-define(FAIL(R), exit(R)). + +-define(MINS(M), timer:minutes(M)). +-define(SECS(S), timer:seconds(S)). + +-define(TT(T), ct:timetrap(T)). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. + +all() -> + Groups = [{api, "ENET_TEST_API", include}], + [use_group(Group, Env, Default) || {Group, Env, Default} <- Groups]. + +use_group(Group, Env, Default) -> + case os:getenv(Env) of + false when (Default =:= include) -> + [{group, Group}]; + false -> + []; + Val -> + case list_to_atom(string:to_lower(Val)) of + Use when (Use =:= include) orelse + (Use =:= enable) orelse + (Use =:= true) -> + [{group, Group}]; + _ -> + [] + end + end. + + +groups() -> + [{api, [], api_cases()}, + {api_basic, [], api_basic_cases()} + + %% {tickets, [], ticket_cases()} + ]. + +api_cases() -> + [ + {group, api_basic} + ]. + +api_basic_cases() -> + [ + api_b_gethostname, + api_b_name_and_addr_info, + api_b_name_and_index + ]. + +%% ticket_cases() -> +%% []. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init_per_suite(Config) -> + case os:type() of + {win32, _} -> + not_yet_implemented(); + _ -> + %% ?LOGGER:start(), + Config + end. + +end_per_suite(_) -> + %% ?LOGGER:stop(), + ok. + +init_per_group(_Group, Config) -> + Config. + +end_per_group(_Group, Config) -> + Config. + + +init_per_testcase(_TC, Config) -> + Config. + +end_per_testcase(_TC, Config) -> + Config. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% API BASIC %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Get the hostname of the host. +api_b_gethostname(suite) -> + []; +api_b_gethostname(doc) -> + []; +api_b_gethostname(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(api_b_gethostname, + fun() -> + ok = api_b_gethostname() + end). + + +api_b_gethostname() -> + case net:gethostname() of + {ok, Hostname} -> + i("hostname: ~s", [Hostname]), + ok; + {error, Reason} -> + ?FAIL(Reason) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Get name and address info. +api_b_name_and_addr_info(suite) -> + []; +api_b_name_and_addr_info(doc) -> + []; +api_b_name_and_addr_info(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(api_b_name_and_addr_info, + fun() -> + ok = api_b_name_and_addr_info() + end). + + +api_b_name_and_addr_info() -> + Domain = inet, + Addr = which_local_addr(Domain), + SA = #{family => Domain, addr => Addr}, + Hostname = + case net:getnameinfo(SA) of + {ok, #{host := Name, service := Service} = NameInfo} + when is_list(Name) andalso is_list(Service) -> + i("getnameinfo: " + "~n ~p", [NameInfo]), + Name; + {ok, BadNameInfo} -> + ?FAIL({getnameinfo, SA, BadNameInfo}); + {error, Reason1} -> + ?FAIL({getnameinfo, SA, Reason1}) + end, + case net:getaddrinfo(Hostname) of + {ok, AddrInfos} when is_list(AddrInfos) -> + i("getaddrinfo: " + "~n ~p", [AddrInfos]), + verify_addr_info(AddrInfos, Domain); + {ok, BadAddrInfo} -> + ?FAIL({getaddrinfo, Hostname, BadAddrInfo}); + {error, Reason2} -> + ?FAIL({getaddrinfo, Hostname, Reason2}) + end. + + +verify_addr_info(AddrInfos, Domain) when (AddrInfos =/= []) -> + verify_addr_info2(AddrInfos, Domain). + +verify_addr_info2([], _Domain) -> + ok; +verify_addr_info2([#{addr := #{addr := Addr, family := Domain, port := Port}, + family := Domain, + type := _Type, + protocol := _Proto}|T], Domain) + when is_integer(Port) andalso + (((Domain =:= inet) andalso is_tuple(Addr) andalso (size(Addr) =:= 4)) orelse + ((Domain =:= inet6) andalso is_tuple(Addr) andalso (size(Addr) =:= 8))) -> + verify_addr_info2(T, Domain); +verify_addr_info2([BadAddrInfo|_], Domain) -> + ?FAIL({bad_address_info, BadAddrInfo, Domain}). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Verify (interface) name and index functions. +%% if_names/0, +%% if_name2index/1 +%% if_index2name/1 +api_b_name_and_index(suite) -> + []; +api_b_name_and_index(doc) -> + []; +api_b_name_and_index(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(api_b_name_and_index, + fun() -> + ok = api_b_name_and_index() + end). + + +api_b_name_and_index() -> + Names = + case net:if_names() of + {ok, N} when is_list(N) andalso (N =/= []) -> + N; + {error, Reason} -> + ?FAIL({if_names, Reason}) + end, + verify_if_names(Names). + +verify_if_names([]) -> + ok; +verify_if_names([{Index, Name}|T]) -> + case net:if_name2index(Name) of + {ok, Index} -> + ok; + {ok, BadIndex} -> + ?FAIL({name2index, Name, Index, BadIndex}); + {error, ReasonN2I} -> + ?FAIL({name2index, Name, ReasonN2I}) + end, + case net:if_index2name(Index) of + {ok, Name} -> + ok; + {ok, BadName} -> + ?FAIL({index2name, Index, Name, BadName}); + {error, ReasonI2N} -> + ?FAIL({index2name, Index, ReasonI2N}) + end, + verify_if_names(T). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% local_host() -> +%% try net_adm:localhost() of +%% Host when is_list(Host) -> +%% %% Convert to shortname if long +%% case string:tokens(Host, [$.]) of +%% [H|_] -> +%% list_to_atom(H) +%% end +%% catch +%% C:E:S -> +%% erlang:raise(C, E, S) +%% end. + + +%% This gets the local address (not 127.0...) +%% We should really implement this using the (new) net module, +%% but until that gets the necessary functionality... +which_local_addr(Domain) -> + case inet:getifaddrs() of + {ok, IFL} -> + which_addr(Domain, IFL); + {error, Reason} -> + ?FAIL({inet, getifaddrs, Reason}) + end. + +which_addr(_Domain, []) -> + ?FAIL(no_address); +which_addr(Domain, [{"lo" ++ _, _}|IFL]) -> + which_addr(Domain, IFL); +which_addr(Domain, [{_Name, IFO}|IFL]) -> + case which_addr2(Domain, IFO) of + {ok, Addr} -> + Addr; + {error, no_address} -> + which_addr(Domain, IFL) + end; +which_addr(Domain, [_|IFL]) -> + which_addr(Domain, IFL). + +which_addr2(_Domain, []) -> + {error, no_address}; +which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) -> + {ok, Addr}; +which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) -> + {ok, Addr}; +which_addr2(Domain, [_|IFO]) -> + which_addr2(Domain, IFO). + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +not_yet_implemented() -> + skip("not yet implemented"). + +skip(Reason) -> + throw({skip, Reason}). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% t() -> +%% os:timestamp(). + + +%% tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) -> +%% T1 = A1*1000000000+B1*1000+(C1 div 1000), +%% T2 = A2*1000000000+B2*1000+(C2 div 1000), +%% T2 - T1. + + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp({_N1, _N2, _N3} = TS) -> + {_Date, Time} = calendar:now_to_local_time(TS), + %% {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + %% FormatTS = + %% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~w", + %% [YYYY, MM, DD, Hour, Min, Sec, N3]), + FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w", [Hour, Min, Sec]), + lists:flatten(FormatTS). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +set_tc_name(N) when is_atom(N) -> + set_tc_name(atom_to_list(N)); +set_tc_name(N) when is_list(N) -> + put(tc_name, N). + +%% get_tc_name() -> +%% get(tc_name). + +tc_begin(TC) -> + set_tc_name(TC), + tc_print("begin ***", + "~n----------------------------------------------------~n", ""). + +tc_end(Result) when is_list(Result) -> + tc_print("done: ~s", [Result], + "", "----------------------------------------------------~n~n"), + ok. + + +tc_try(Case, Fun) when is_atom(Case) andalso is_function(Fun, 0) -> + tc_begin(Case), + try + begin + Fun(), + ?SLEEP(?SECS(1)), + tc_end("ok") + end + catch + throw:{skip, _} = SKIP -> + tc_end("skipping"), + SKIP; + Class:Error:Stack -> + tc_end("failed"), + erlang:raise(Class, Error, Stack) + end. + + +tc_print(F, Before, After) -> + tc_print(F, [], Before, After). + +tc_print(F, A, Before, After) -> + Name = tc_which_name(), + FStr = f("*** [~s][~s][~p] " ++ F ++ "~n", + [formated_timestamp(),Name,self()|A]), + io:format(user, Before ++ FStr ++ After, []). + +tc_which_name() -> + case get(tc_name) of + undefined -> + case get(sname) of + undefined -> + ""; + SName when is_list(SName) -> + SName + end; + Name when is_list(Name) -> + Name + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% l2a(S) when is_list(S) -> +%% list_to_atom(S). + +%% l2b(L) when is_list(L) -> +%% list_to_binary(L). + +%% b2l(B) when is_binary(B) -> +%% binary_to_list(B). + +f(F, A) -> + lists:flatten(io_lib:format(F, A)). + + +%% i(F) -> +%% i(F, []). + +i(F, A) -> + FStr = f("[~s] " ++ F, [formated_timestamp()|A]), + io:format(user, FStr ++ "~n", []), + io:format(FStr, []). + -- cgit v1.2.3