File 2424-kernel-enet-test-Add-prim_net-test-suite.patch of Package erlang

From 79ac912814dfaa9655ae1ccb8c8753f934fed357 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Tue, 27 May 2025 18:32:32 +0200
Subject: [PATCH 04/14] [kernel|enet|test] Add prim_net test suite

Add prim_net test suite, with one initial test case: get-adapters-adderesses

OTP-19674
---
 lib/kernel/test/Makefile           |   1 +
 lib/kernel/test/prim_net_SUITE.erl | 547 +++++++++++++++++++++++++++++
 2 files changed, 548 insertions(+)
 create mode 100644 lib/kernel/test/prim_net_SUITE.erl

diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index fffec45314..726ecaea03 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -117,6 +117,7 @@ MODULES= \
 	logger_stress_SUITE \
 	logger_test_lib \
 	net_SUITE \
+	prim_net_SUITE \
 	os_SUITE \
 	pg_SUITE \
 	rtnode \
diff --git a/lib/kernel/test/prim_net_SUITE.erl b/lib/kernel/test/prim_net_SUITE.erl
new file mode 100644
index 0000000000..9fd3a20432
--- /dev/null
+++ b/lib/kernel/test/prim_net_SUITE.erl
@@ -0,0 +1,547 @@
+%%
+%% %CopyrightBegin%
+%%
+%% SPDX-License-Identifier: Apache-2.0
+%% 
+%% Copyright Ericsson AB 2025-2025. 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%
+%%
+
+%% Note that some of the functions exported by prim_net only works on unnix
+%% and others only on Windows.
+
+%% SUITE = prim_net_SUITE
+%% Run the entire test suite: 
+%% ts:run(kernel, prim_net_SUITE, [batch]).
+%%
+%% Run a specific group:
+%% ts:run(kernel, prim_net_SUITE, {group, foo}, [batch]).
+%%
+%% Run a specific test case:
+%% ts:run(kernel, prim_net_SUITE, foo, [batch]).
+%%
+%% (cd /mnt/c/$LOCAL_TESTS/26/kernel_test/ && $ERL_TOP/bin/win32/erl.exe -sname kernel-26-tester -pa c:$LOCAL_TESTS/26/test_server)
+%% application:set_env(kernel, test_inet_backends, true).
+%%
+%% S = fun() -> ts:run(kernel, prim_net_SUITE, [batch]) end.
+%% S = fun(SUITE) -> ts:run(kernel, SUITE, [batch]) end.
+%% G = fun(GROUP) -> ts:run(kernel, prim_net_SUITE, {group, GROUP}, [batch]) end.
+%% G = fun(SUITE, GROUP) -> ts:run(kernel, SUITE, {group, GROUP}, [batch]) end.
+%% T = fun(TC) -> ts:run(kernel, prim_net_SUITE, TC, [batch]) end.
+%%
+%% S = fun() -> ct:run_test([{suite, prim_net_SUITE}]) end.
+%% S = fun(SUITE) -> ct:run_test([{suite, SUITE}]) end.
+%% G = fun(GROUP) -> ct:run_test([{suite, prim_net_SUITE}, {group, GROUP}]) end.
+%% G = fun(SUITE, GROUP) -> ct:run_test([{suite, SUITE}, {group, GROUP}]) end.
+%% T = fun(TC) -> ct:run_test([{suite, prim_net_SUITE}, {testcase, TC}]) end.
+%% T = fun(S, TC) -> ct:run_test([{suite, S}, {testcase, TC}]) end.
+%% T = fun(G, TC) -> ct:run_test([{suite, prim_net_SUITE}, {group, G}, {testcase, TC}]) end.
+%% T = fun(S, G, TC) -> ct:run_test([{suite, S}, {group, G}, {testcase, TC}]) end.
+%%
+%% Some official info about AF_UNIX
+%% https://devblogs.microsoft.com/commandline/windowswsl-interop-with-af_unix/
+
+
+
+-module(prim_net_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+-include("socket_test_evaluator.hrl").
+-include("kernel_test_lib.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([
+         get_adapters_addresses/1
+        ]).
+
+
+%% Internal exports
+%% -export([]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+suite() ->
+    [{ct_hooks, [ts_install_cth]},
+     {timetrap, {minutes,1}}].
+
+all() -> 
+    [
+     {group, misc}
+    ].
+
+
+groups() ->     
+    [
+     {misc, [], misc_cases()}
+    ].
+
+
+misc_cases() ->
+    [
+     get_adapters_addresses
+    ].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init_per_suite(Config0) ->
+    ?P("init_per_suite -> entry with"
+       "~n      Config: ~p"
+       "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
+    
+    try net:info() of
+        #{} ->
+            case ?LIB:init_per_suite(Config0) of
+                {skip, _} = SKIP ->
+                    SKIP;
+
+                Config1 when is_list(Config1) ->
+
+                    ?P("init_per_suite -> end when "
+                       "~n      Config: ~p", [Config1]),
+
+                    ?ENSURE_NOT_DOG_SLOW(Config1, 15),
+
+                    %% We need a monitor on this node also
+                    kernel_test_sys_monitor:start(),
+
+                    Config1
+            end
+    catch
+        error : notsup ->
+            {skip, "enet not supported"};
+        error : undef ->
+            {skip, "enet not configured"}
+    end.
+
+end_per_suite(Config0) ->
+
+    ?P("end_per_suite -> entry with"
+       "~n      Config: ~p"
+       "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
+
+    %% Stop the local monitor
+    kernel_test_sys_monitor:stop(),
+
+    Config1 = ?LIB:end_per_suite(Config0),
+
+    ?P("end_per_suite -> "
+       "~n      Nodes: ~p", [erlang:nodes()]),
+
+    Config1.
+
+
+init_per_group(_GroupName, Config) ->
+    io:format("init_per_group(~w) -> entry with"
+              "~n   Config: ~p"
+              "~n", [_GroupName, Config]),
+    Config.
+
+end_per_group(_GroupName, Config) ->
+    Config.
+
+
+init_per_testcase(_TC, Config) ->
+    io:format("init_per_testcase(~w) -> entry with"
+              "~n   Config: ~p"
+              "~n", [_TC, Config]),
+    Config.
+
+end_per_testcase(_TC, Config) ->
+    Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%                                                                     %%
+%%                               MISC                                  %%
+%%                                                                     %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% There is no way we can test every possible combination of args,
+%% so we just test a new simple examples.
+
+get_adapters_addresses(_Config) when is_list(_Config) ->
+    ?TT(?SECS(10)),
+    tc_try(?FUNCTION_NAME,
+	   fun() -> ok end,
+           fun() ->
+                   ok = do_get_adapters_addresses()
+           end).
+
+
+do_get_adapters_addresses() ->
+    L = [
+	 #{},
+         default,
+         no_skips_all_includes,
+	 no_skips_no_includes,
+         all_skips_no_includes,
+	 all_skips_all_includes,
+	 %% We only test this one thing; *one* flag
+	 %% In the case of addresses, we also add family
+	 #{flags => #{skip_unicast => true}},
+	 #{flags => #{skip_unicast => false}},
+	 #{family => unspec,
+	   flags => #{skip_unicast => false}},
+	 #{family => inet,
+	   flags => #{skip_unicast => false}},
+	 #{family => inet6,
+	   flags => #{skip_unicast => false}},
+	 #{flags => #{skip_anycast => true}},
+	 #{flags => #{skip_anycast => false}},
+	 #{family => unspec,
+	   flags => #{skip_anycast => false}},
+	 #{family => inet,
+	   flags => #{skip_anycast => false}},
+	 #{family => inet6,
+	   flags => #{skip_anycast => false}},
+	 #{flags => #{skip_multicast => true}},
+	 #{flags => #{skip_multicast => false}},
+	 #{flags => #{skip_dns_server => true}},
+	 #{flags => #{skip_dns_server => false}},
+	 #{family => unspec,
+	   flags => #{skip_dns_server => false}},
+	 #{family => inet,
+	   flags => #{skip_dns_server => false}},
+	 #{family => inet6,
+	   flags => #{skip_dns_server => false}},
+	 #{flags => #{include_prefix => true}},
+	 #{flags => #{include_prefix => false}},
+	 #{family => unspec,
+	   flags => #{include_prefix => false}},
+	 #{family => inet,
+	   flags => #{include_prefix => false}},
+	 #{family => inet6,
+	   flags => #{include_prefix => false}}%% ,
+	 %% #{flags => #{include_wins_info => true}},
+	 %% #{flags => #{include_gateways => true}}
+	],
+    try
+        do_get_adapters_addresses(L)
+    catch
+        error:notsup = NOTSUP ->
+            skip(NOTSUP)
+    end.
+
+do_get_adapters_addresses([]) ->
+    ok;
+do_get_adapters_addresses([H | T]) ->
+    ?P("try gaa with: "
+       "~n   Args: ~p", [H]),    
+    case prim_net:get_adapters_addresses(H) of
+        {ok, Adapters} when is_list(Adapters) ->
+	    gaa_verify_adapter_addrs(H, Adapters),
+            do_get_adapters_addresses(T);
+
+        {error, Reason} ->
+	    ?P("unexpected failure: "
+	       "~n   Flags:  ~p"
+	       "~n   Reason: ~p", [H, Reason]),
+            exit({unexpected_failure, Reason})
+    end.
+
+
+%% This is **very** basic
+gaa_verify_adapter_addrs(default = _Filter,
+			 Adapters)
+  when is_list(Adapters) andalso (Adapters =/= []) ->
+    ok;
+gaa_verify_adapter_addrs(no_skips_all_includes = _Filter,
+			 Adapters)
+  when is_list(Adapters) andalso (Adapters =/= []) ->
+    ok;
+gaa_verify_adapter_addrs(no_skips_no_includes = _Filter,
+			 Adapters)
+  when is_list(Adapters) andalso (Adapters =/= []) ->
+    ok;
+gaa_verify_adapter_addrs(all_skips_no_includes = _Filter,
+			 Adapters)
+  when is_list(Adapters) andalso (Adapters =/= []) ->
+    ok;
+gaa_verify_adapter_addrs(all_skips_all_includes = _Filter,
+			 Adapters)
+  when is_list(Adapters) andalso (Adapters =/= []) ->
+    ok;
+gaa_verify_adapter_addrs(#{family := Fam,
+			   flags  := Flags},
+			 Adapters) ->
+    gaa_verify_adapter_addrs_flags(Adapters, Flags, Fam);
+gaa_verify_adapter_addrs(#{flags  := Flags},
+			 Adapters) ->
+    gaa_verify_adapter_addrs_flags(Adapters, Flags, undefined);
+gaa_verify_adapter_addrs(_, _) ->
+    ok.
+
+gaa_verify_adapter_addrs_flags(Adapters, Flags, Fam) ->
+    case Flags of
+	#{skip_anycast := SkipAC} ->
+	    gaa_verify_anycast(Adapters, SkipAC, Fam);
+	#{skip_unicast := SkipUC} ->
+	    gaa_verify_unicast(Adapters, SkipUC, Fam);
+	#{skip_multicast := SkipMC} ->
+	    gaa_verify_multicast(Adapters, SkipMC, Fam);
+	#{skip_dns_server := SkipDS} ->
+	    gaa_verify_dns_servers(Adapters, SkipDS, Fam);
+	#{include_prefix := IncPref} ->
+	    gaa_verify_include_prefix(Adapters, IncPref, Fam)%% ;
+	%% #{include_wins_info := true} ->
+	%%     ?P("include_wins_info ->"
+	%%        "~n   ~p", [Adapters]),
+	%%     ok;
+	%% #{include_gateways := true} ->
+	%%     ?P("include_gateways ->"
+	%%        "~n   ~p", [Adapters]),
+	%%     ok
+    end.
+    
+
+gaa_verify_anycast([], __SkipAC, _Fam) ->
+    ok;
+gaa_verify_anycast([#{name          := Name,
+		      anycast_addrs := []} | Adapters],
+		   SkipAC, Fam) when (SkipAC =:= true) ->
+    ?P("(no) anycast addrs verified for ~p", [Name]),
+    gaa_verify_anycast(Adapters, SkipAC, Fam);
+gaa_verify_anycast([#{name          := Name,
+		      anycast_addrs := Addrs} | Adapters],
+		   SkipAC, Fam) ->
+    gaa_verify_addrs(Addrs, Fam),
+    ?P("anycast addrs (~w) verified for ~p:"
+       "~n   ~p", [Fam, Name, Addrs]),
+    gaa_verify_anycast(Adapters, SkipAC, Fam);
+gaa_verify_anycast([#{name := Name} = Adapter | _Adapters], _SkipAC, _Fam) ->
+    ?P("anycast verification failed for ~p: "
+       "~n   ~p", [Name, Adapter]),
+    exit({unexpected_anycast, Name}).
+
+
+gaa_verify_unicast([], _SkipUC, _Fam) ->
+    ok;
+gaa_verify_unicast([#{name          := Name,
+		      unicast_addrs := []} | Adapters],
+		   SkipUC, Fam) when (SkipUC =:= true) ->
+    ?P("(no) unicast addrs verified for ~p", [Name]),
+    gaa_verify_unicast(Adapters, SkipUC, Fam);
+gaa_verify_unicast([#{name          := Name,
+		      unicast_addrs := Addrs} | Adapters],
+		   SkipAC, Fam) ->
+    gaa_verify_addrs(Addrs, Fam),
+    ?P("unicast addrs (~w) verified for ~p:"
+       "~n   ~p", [Fam, Name, Addrs]),
+    gaa_verify_unicast(Adapters, SkipAC, Fam);
+gaa_verify_unicast([#{name := Name} = Adapter| _Adapters],
+		   _SkipUC, _Fam) ->
+    ?P("unicast verification failed for ~p: "
+       "~n   ~p", [Name, Adapter]),
+    exit({unexpected_unicast, Name}).
+
+
+gaa_verify_multicast([], _SkipMC, _Fam) ->
+    ok;
+gaa_verify_multicast([#{name            := Name,
+			multicast_addrs := []} | Adapters],
+		     SkipMC, Fam) when (SkipMC =:= true) ->
+    ?P("(no) multicast addrs verified for ~p", [Name]),
+    gaa_verify_multicast(Adapters, SkipMC, Fam);
+gaa_verify_multicast([#{name            := Name,
+			multicast_addrs := Addrs} | Adapters],
+		     SkipMC, Fam) ->
+    gaa_verify_addrs(Addrs, Fam),
+    ?P("multicast addrs (~w) verified for ~p:"
+       "~n   ~p", [Fam, Name, Addrs]),
+    gaa_verify_multicast(Adapters, SkipMC, Fam);
+gaa_verify_multicast([#{name := Name} = Adapter | _Adapters],
+		     _SkipMC, Fam) ->
+    ?P("multicast (~w) verification failed for ~p: "
+       "~n   ~p", [Fam, Name, Adapter]),
+    exit({unexpected_multicast, Name}).
+
+
+gaa_verify_dns_servers([], _SkipMC, _Fam) ->
+    ok;
+gaa_verify_dns_servers([#{name        := Name,
+			  dns_server_addrs := []} | Adapters],
+		       SkipDS, Fam) when (SkipDS =:= true) ->
+    ?P("(no) dns-servers verified for ~p", [Name]),
+    gaa_verify_dns_servers(Adapters, SkipDS, Fam);
+gaa_verify_dns_servers([#{name             := Name,
+			  dns_server_addrs := Addrs} | Adapters],
+		       SkipDS, Fam) ->
+    gaa_verify_addrs(Addrs, Fam),
+    ?P("dns-servers (~w) verified for ~p:"
+       "~n   ~p", [Fam, Name, Addrs]),
+    gaa_verify_dns_servers(Adapters, SkipDS, Fam);
+gaa_verify_dns_servers([#{name := Name} = Adapter | _Adapters],
+		       SkipDS, Fam) ->
+    ?P("dns-servers (~w) verification failed for ~p: "
+       "~n   SkipDS:  ~p"
+       "~n   Adapter: ~p", [Fam, Name, SkipDS, Adapter]),
+    exit({unexpected_dns_servers, Name}).
+
+
+gaa_verify_include_prefix([], _IncPref, _Fam) ->
+    ok;
+gaa_verify_include_prefix([#{name     := Name,
+			     prefixes := []} | Adapters],
+			  IncPref, Fam) when (IncPref =:= false) ->
+    ?P("(do not) include-prefix verified for ~p", [Name]),
+    gaa_verify_include_prefix(Adapters, IncPref, Fam);
+gaa_verify_include_prefix([#{name     := Name,
+			     prefixes := Prefs} | Adapters],
+			  IncPref, Fam) ->
+    %% Prefixes are not the same as addresses,
+    %% but content is similar enough that we can use the same function...
+    gaa_verify_addrs(Prefs, Fam),
+    ?P("include-prefix (~w) verified for ~p:"
+       "~n   ~p", [Fam, Name, Prefs]),
+    gaa_verify_include_prefix(Adapters, IncPref, Fam);
+gaa_verify_include_prefix([#{name := Name} = Adapter | _Adapters],
+			  IncPref, Fam) ->
+    ?P("include-prefix (~w) verification failed for ~p: "
+       "~n   IncPref: ~p"
+       "~n   Adapter: ~p", [Fam, Name, IncPref, Adapter]),
+    exit({unexpected_include_prefix, Name}).
+
+
+gaa_verify_addrs([], _Fam) ->
+    ok;
+gaa_verify_addrs([Addr|Addrs], FilterFam) ->
+    gaa_verify_addr(Addr, FilterFam),
+    gaa_verify_addrs(Addrs, FilterFam).
+
+gaa_verify_addr(#{addr := #{addr   := _,
+			    family := _}},
+		undefined = _Fam) ->
+    ok;
+gaa_verify_addr(#{addr := #{addr   := Addr,
+			    family := Fam}},
+		FilterFam)
+  when (FilterFam =:= inet) andalso
+       (FilterFam =:= Fam) andalso
+       is_tuple(Addr) andalso (tuple_size(Addr) =:= 4) ->
+    ok;
+gaa_verify_addr(#{addr := #{addr   := Addr,
+			    family := Fam}},
+		FilterFam)
+  when (FilterFam =:= inet6) andalso
+       (FilterFam =:= Fam) andalso
+       is_tuple(Addr) andalso (tuple_size(Addr) =:= 8) ->
+    ok;
+%% If filter-fam is unspec, the address family can be *either* inet *or* inet6
+gaa_verify_addr(#{addr := #{addr   := Addr,
+			    family := Fam}},
+		FilterFam)
+  when (FilterFam =:= unspec) andalso
+       (((Fam =:= inet) andalso
+	 is_tuple(Addr) andalso (tuple_size(Addr) =:= 4)) orelse
+	((Fam =:= inet6) andalso
+	 is_tuple(Addr) andalso (tuple_size(Addr) =:= 8))) ->
+    ok;
+gaa_verify_addr(Addr, FilterFam) ->
+    ?P("Failed verify address: "
+       "~n   Filter Family: ~p"
+       "~n   Address:       ~p", [Addr, FilterFam]),
+    exit({unexpected_address, FilterFam}).
+    
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% 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) ->
+%%     ?LIB:which_local_addr(Domain).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% monitored_by() ->
+%%     monitored_by(self()).
+%% monitored_by(Pid) ->	
+%%     {monitored_by, Refs} = erlang:process_info(Pid, monitored_by),
+%%     Refs.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% not_supported(What) ->
+%%     skip({not_supported, What}).
+
+%% not_yet_implemented() ->
+%%     skip("not yet implemented").
+
+skip(Reason) ->
+    throw({skip, Reason}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% *** tc_try/2,3 ***
+%% Case:      Basically the test case name
+%% TCCondFun: A fun that is evaluated before the actual test case
+%%            The point of this is that it can performs checks to
+%%            see if we shall run the test case at all.
+%%            For instance, the test case may only work in specific
+%%            conditions.
+%% FCFun:     The test case fun
+tc_try(Case, TCFun) ->
+    ?TC_TRY(Case, TCFun).
+
+tc_try(Case, TCCondFun, TCFun) ->
+    ?TC_TRY(Case, TCCondFun, TCFun).
+   
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% i(F) ->
+%%     i(F, []).
+
+%% i(F, A) ->
+%%     FStr = ?F("[~s] " ++ F, [?FTS()|A]),
+%%     io:format(user, FStr ++ "~n", []),
+%%     io:format(FStr, []).
+
-- 
2.43.0

openSUSE Build Service is sponsored by