%% %% %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... %% Also we should really call prim_net directly, and not net (since that does %% not even reside here). %% %% 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) -> %% We test on the socket module for simplicity case lists:member(socket, erlang:loaded()) of true -> case os:type() of {win32, _} -> not_yet_implemented(); _ -> %% ?LOGGER:start(), Config end; false -> {skip, "esock disabled"} 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([#{family := DomainA}|T], DomainB) when (DomainA =/= DomainB) -> %% Ignore entries for other domains verify_addr_info2(T, DomainB); 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, []) -> skip(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, []).