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