1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2019-2020. 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%% This test suite is basically a "placeholder" for a proper test suite...
23%% Also we should really call prim_net directly, and not net (since that does
24%% not even reside here).
25%%
26
27%% Run the entire test suite:
28%% ts:run(emulator, net_SUITE, [batch]).
29%%
30%% Run a specific group:
31%% ts:run(emulator, net_SUITE, {group, foo}, [batch]).
32%%
33%% Run a specific test case:
34%% ts:run(emulator, net_SUITE, foo, [batch]).
35
36-module(net_SUITE).
37
38-include_lib("common_test/include/ct.hrl").
39-include_lib("common_test/include/ct_event.hrl").
40
41%% Suite exports
42-export([suite/0, all/0, groups/0]).
43-export([init_per_suite/1,    end_per_suite/1,
44         init_per_group/2,    end_per_group/2,
45         init_per_testcase/2, end_per_testcase/2]).
46
47%% Test cases
48-export([
49         %% *** API Basic ***
50         api_b_gethostname/1,
51         api_b_getifaddrs/1,
52         api_b_name_and_addr_info/1,
53
54         api_b_name_and_index/1
55
56         %% Tickets
57        ]).
58
59
60%% -include("socket_test_evaluator.hrl").
61
62%% Internal exports
63%% -export([]).
64
65
66%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67
68-define(SLEEP(T), receive after T -> ok end).
69
70-define(FAIL(R), exit(R)).
71-define(SKIP(R), throw({skip, R})).
72
73-define(MINS(M), timer:minutes(M)).
74-define(SECS(S), timer:seconds(S)).
75
76-define(TT(T),   ct:timetrap(T)).
77
78
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80
81suite() ->
82    [{ct_hooks,[ts_install_cth]},
83     {timetrap,{minutes,1}}].
84
85all() ->
86    Groups = [{api, "ENET_TEST_API", include}],
87    [use_group(Group, Env, Default) || {Group, Env, Default} <- Groups].
88
89use_group(Group, Env, Default) ->
90	case os:getenv(Env) of
91	    false when (Default =:= include) ->
92		[{group, Group}];
93	    false ->
94		[];
95	    Val ->
96		case list_to_atom(string:to_lower(Val)) of
97		    Use when (Use =:= include) orelse
98			     (Use =:= enable) orelse
99			     (Use =:= true) ->
100			[{group, Group}];
101		    _ ->
102			[]
103		end
104	end.
105
106
107groups() ->
108    [{api,       [], api_cases()},
109     {api_basic, [], api_basic_cases()}
110
111     %% {tickets, [], ticket_cases()}
112    ].
113
114api_cases() ->
115    [
116     {group, api_basic}
117    ].
118
119api_basic_cases() ->
120    [
121     api_b_gethostname,
122     api_b_getifaddrs,
123     api_b_name_and_addr_info,
124     api_b_name_and_index
125    ].
126
127%% ticket_cases() ->
128%%     [].
129
130
131
132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133
134init_per_suite(Config) ->
135    try net:info() of
136        #{} ->
137            %% ?LOGGER:start(),
138            Config
139    catch
140        error : notsup ->
141            {skip, "esock not supported"}
142    end.
143
144end_per_suite(_) ->
145    %% ?LOGGER:stop(),
146    ok.
147
148init_per_group(_Group, Config) ->
149    Config.
150
151end_per_group(_Group, Config) ->
152    Config.
153
154
155init_per_testcase(_TC, Config) ->
156    Config.
157
158end_per_testcase(_TC, Config) ->
159    Config.
160
161
162
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165%%                                                                     %%
166%%                           API BASIC                                 %%
167%%                                                                     %%
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172
173%% Get the hostname of the host.
174api_b_gethostname(suite) ->
175    [];
176api_b_gethostname(doc) ->
177    [];
178api_b_gethostname(_Config) when is_list(_Config) ->
179    ?TT(?SECS(5)),
180    tc_try(api_b_gethostname,
181           fun() ->
182                   ok = api_b_gethostname()
183           end).
184
185
186api_b_gethostname() ->
187    case net:gethostname() of
188        {ok, Hostname} ->
189            i("hostname: ~s", [Hostname]),
190            ok;
191        {error, Reason} ->
192            ?FAIL(Reason)
193    end.
194
195
196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197
198%% This is a *very* basic test. It simply calls the function and expect
199%% it to succeed...
200api_b_getifaddrs(suite) ->
201    [];
202api_b_getifaddrs(doc) ->
203    [];
204api_b_getifaddrs(_Config) when is_list(_Config) ->
205    ?TT(?SECS(5)),
206    tc_try(api_b_getifaddrs,
207           fun() ->
208                   ok = api_b_getifaddrs()
209           end).
210
211
212api_b_getifaddrs() ->
213    case net:getifaddrs() of
214        {ok, IfAddrs} ->
215            i("IfAddrs: "
216              "~n   ~p", [IfAddrs]),
217            ok;
218        {error, enotsup = Reason} ->
219            i("getifaddrs not supported - skipping"),
220            skip(Reason);
221        {error, Reason} ->
222            ?FAIL(Reason)
223    end.
224
225
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227
228%% Get name and address info.
229api_b_name_and_addr_info(suite) ->
230    [];
231api_b_name_and_addr_info(doc) ->
232    [];
233api_b_name_and_addr_info(_Config) when is_list(_Config) ->
234    ?TT(?SECS(5)),
235    tc_try(api_b_name_and_addr_info,
236           fun() ->
237                   ok = api_b_name_and_addr_info()
238           end).
239
240
241api_b_name_and_addr_info() ->
242    Domain = inet,
243    Addr   = which_local_addr(Domain),
244    SA     = #{family => Domain, addr => Addr},
245    Hostname =
246        case net:getnameinfo(SA) of
247            {ok, #{host := Name, service := Service} = NameInfo}
248              when is_list(Name) andalso is_list(Service) ->
249                i("getnameinfo: "
250                  "~n   ~p", [NameInfo]),
251                Name;
252            {ok, BadNameInfo} ->
253                ?FAIL({getnameinfo, SA, BadNameInfo});
254            {error, enotsup = ReasonNI} ->
255                i("getnameinfo not supported - skipping"),
256                ?SKIP({getnameinfo, ReasonNI});
257            {error, Reason1} ->
258                ?FAIL({getnameinfo, SA, Reason1})
259        end,
260    case net:getaddrinfo(Hostname) of
261        {ok, AddrInfos} when is_list(AddrInfos) ->
262            i("getaddrinfo: "
263              "~n   ~p", [AddrInfos]),
264            verify_addr_info(AddrInfos, Domain);
265        {ok, BadAddrInfo} ->
266            ?FAIL({getaddrinfo, Hostname, BadAddrInfo});
267        {error, enotsup = ReasonAI} ->
268            i("getaddrinfo not supported - skipping"),
269            ?SKIP({getaddrinfo, ReasonAI});
270        {error, Reason2} ->
271            ?FAIL({getaddrinfo, Hostname, Reason2})
272    end.
273
274
275verify_addr_info(AddrInfos, Domain) when (AddrInfos =/= []) ->
276    verify_addr_info2(AddrInfos, Domain).
277
278verify_addr_info2([], _Domain) ->
279    ok;
280verify_addr_info2([#{addr     := #{addr   := Addr,
281				   family := Domain,
282				   port   := Port},
283                     family   := Domain,
284                     type     := _Type,
285                     protocol := _Proto}|T], Domain)
286  when is_integer(Port) andalso
287       (((Domain =:= inet) andalso is_tuple(Addr) andalso (size(Addr) =:= 4)) orelse
288        ((Domain =:= inet6) andalso is_tuple(Addr) andalso (size(Addr) =:= 8))) ->
289    verify_addr_info2(T, Domain);
290verify_addr_info2([#{family := DomainA}|T], DomainB)
291  when (DomainA =/= DomainB) ->
292    %% Ignore entries for other domains
293    verify_addr_info2(T, DomainB);
294verify_addr_info2([BadAddrInfo|_], Domain) ->
295    ?FAIL({bad_address_info, BadAddrInfo, Domain}).
296
297
298
299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300
301%% Verify (interface) name and index functions.
302%% if_names/0,
303%% if_name2index/1
304%% if_index2name/1
305api_b_name_and_index(suite) ->
306    [];
307api_b_name_and_index(doc) ->
308    [];
309api_b_name_and_index(_Config) when is_list(_Config) ->
310    ?TT(?SECS(5)),
311    tc_try(api_b_name_and_index,
312           fun() ->
313                   ok = api_b_name_and_index()
314           end).
315
316
317api_b_name_and_index() ->
318    Names =
319        case net:if_names() of
320            {ok, N} when is_list(N) andalso (N =/= []) ->
321                N;
322            {error, enotsup = Reason} ->
323                i("if_names not supported - skipping"),
324                ?SKIP({if_names, Reason});
325            {error, Reason} ->
326                ?FAIL({if_names, Reason})
327        end,
328    verify_if_names(Names).
329
330verify_if_names([]) ->
331    ok;
332verify_if_names([{Index, Name}|T]) ->
333    case net:if_name2index(Name) of
334        {ok, Index} ->
335            ok;
336        {ok, BadIndex} ->
337            ?FAIL({if_name2index, Name, Index, BadIndex});
338        {error, enotsup = Reason_N2I1} ->
339            i("if_name2index not supported - skipping"),
340            ?SKIP({if_name2index, Reason_N2I1});
341        {error, Reason_N2I2} ->
342            ?FAIL({if_name2index, Name, Reason_N2I2})
343    end,
344    case net:if_index2name(Index) of
345        {ok, Name} ->
346            ok;
347        {ok, BadName} ->
348            ?FAIL({if_index2name, Index, Name, BadName});
349        {error, enotsup = Reason_I2N1} ->
350            i("if_index2name not supported - skipping"),
351            ?SKIP({if_index2name, Reason_I2N1});
352        {error, Reason_I2N2} ->
353            ?FAIL({if_index2name, Index, Reason_I2N2})
354    end,
355    verify_if_names(T).
356
357
358
359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360
361%% This gets the local address (not 127.0...)
362%% We should really implement this using the (new) net module,
363%% but until that gets the necessary functionality...
364which_local_addr(Domain) ->
365    case inet:getifaddrs() of
366        {ok, IFL} ->
367            which_addr(Domain, IFL);
368        {error, Reason} ->
369            ?FAIL({inet, getifaddrs, Reason})
370    end.
371
372which_addr(_Domain, []) ->
373    skip(no_address);
374which_addr(Domain, [{"lo" ++ _, _}|IFL]) ->
375    which_addr(Domain, IFL);
376which_addr(Domain, [{_Name, IFO}|IFL]) ->
377    case which_addr2(Domain, IFO) of
378        {ok, Addr} ->
379            Addr;
380        {error, no_address} ->
381            which_addr(Domain, IFL)
382    end;
383which_addr(Domain, [_|IFL]) ->
384    which_addr(Domain, IFL).
385
386which_addr2(_Domain, []) ->
387    {error, no_address};
388which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
389    {ok, Addr};
390which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
391    {ok, Addr};
392which_addr2(Domain, [_|IFO]) ->
393    which_addr2(Domain, IFO).
394
395
396
397
398
399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
400
401not_yet_implemented() ->
402    skip("not yet implemented").
403
404skip(Reason) ->
405    throw({skip, Reason}).
406
407
408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409
410%% t() ->
411%%     os:timestamp().
412
413
414%% tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) ->
415%%     T1 = A1*1000000000+B1*1000+(C1 div 1000),
416%%     T2 = A2*1000000000+B2*1000+(C2 div 1000),
417%%     T2 - T1.
418
419
420formated_timestamp() ->
421    format_timestamp(os:timestamp()).
422
423format_timestamp({_N1, _N2, _N3} = TS) ->
424    {_Date, Time}   = calendar:now_to_local_time(TS),
425    %% {YYYY,MM,DD}   = Date,
426    {Hour,Min,Sec} = Time,
427    %% FormatTS =
428    %%     io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~w",
429    %%                   [YYYY, MM, DD, Hour, Min, Sec, N3]),
430    FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w", [Hour, Min, Sec]),
431    lists:flatten(FormatTS).
432
433
434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435
436set_tc_name(N) when is_atom(N) ->
437    set_tc_name(atom_to_list(N));
438set_tc_name(N) when is_list(N) ->
439    put(tc_name, N).
440
441%% get_tc_name() ->
442%%     get(tc_name).
443
444tc_begin(TC) ->
445    set_tc_name(TC),
446    tc_print("begin ***",
447             "~n----------------------------------------------------~n", "").
448
449tc_end(Result) when is_list(Result) ->
450    tc_print("done: ~s", [Result],
451             "", "----------------------------------------------------~n~n"),
452    ok.
453
454
455tc_try(Case, Fun) when is_atom(Case) andalso is_function(Fun, 0) ->
456    tc_begin(Case),
457    try
458        begin
459            Fun(),
460            ?SLEEP(?SECS(1)),
461            tc_end("ok")
462        end
463    catch
464        throw:{skip, _} = SKIP ->
465            tc_end("skipping"),
466            SKIP;
467        Class:Error:Stack ->
468            tc_end("failed"),
469            erlang:raise(Class, Error, Stack)
470    end.
471
472
473tc_print(F, Before, After) ->
474    tc_print(F, [], Before, After).
475
476tc_print(F, A, Before, After) ->
477    Name = tc_which_name(),
478    FStr = f("*** [~s][~s][~p] " ++ F ++ "~n",
479             [formated_timestamp(),Name,self()|A]),
480    io:format(user, Before ++ FStr ++ After, []).
481
482tc_which_name() ->
483    case get(tc_name) of
484        undefined ->
485            case get(sname) of
486                undefined ->
487                    "";
488                SName when is_list(SName) ->
489                    SName
490            end;
491        Name when is_list(Name) ->
492            Name
493    end.
494
495
496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497
498%% l2a(S) when is_list(S) ->
499%%     list_to_atom(S).
500
501%% l2b(L) when is_list(L) ->
502%%     list_to_binary(L).
503
504%% b2l(B) when is_binary(B) ->
505%%     binary_to_list(B).
506
507f(F, A) ->
508    lists:flatten(io_lib:format(F, A)).
509
510
511i(F) ->
512    i(F, []).
513
514i(F, A) ->
515    FStr = f("[~s] " ++ F, [formated_timestamp()|A]),
516    io:format(user, FStr ++ "~n", []),
517    io:format(FStr, []).
518
519