File 2502-snmp-test-Update-the-Net-SNMP-test-suite.patch of Package erlang

From 0cf0d9fb4e877eec86edb384180d7f2054ff973b Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Thu, 24 Apr 2025 12:24:07 +0200
Subject: [PATCH 2/9] [snmp|test] Update the Net-SNMP test suite

---
 .gitignore                                    |   2 +
 lib/snmp/test/Makefile                        |  63 +++++--
 lib/snmp/test/modules.mk                      |   3 +
 lib/snmp/test/snmp_to_snmpnet_SUITE.erl       | 177 ++++++++++++++----
 .../OTP-C64-MIB.mib                           | 102 ++++++++++
 5 files changed, 293 insertions(+), 54 deletions(-)
 create mode 100644 lib/snmp/test/snmp_to_snmpnet_SUITE_data/OTP-C64-MIB.mib

diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index 7aa8fa82a4..9b5ee85a77 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -42,17 +42,28 @@ SNMP_ROOT = ..
 
 ERL_FILES = $(MODULES:%=%.erl)
 
-SNMP_TEST_DATA = snmp_test_data
+SNMP_TEST_DATA    = snmp_test_data
+NETSNMP_TEST_DATA = snmp_to_snmpnet_SUITE_data
 
-SNMP_MIB_DIR = $(SNMP_TEST_DATA)
+SNMP_MIB_DIR    = $(SNMP_TEST_DATA)
+NETSNMP_MIB_DIR = $(NETSNMP_TEST_DATA)
 
-SNMP_BIN_TARGET_DIR = $(SNMP_TEST_DATA)
+SNMP_BIN_TARGET_DIR    = $(SNMP_TEST_DATA)
+NETSNMP_BIN_TARGET_DIR = $(NETSNMP_TEST_DATA)
 
-MIB_SOURCE  = $(MIB_FILES:%.mib=$(SNMP_MIB_DIR)/%.mib)
+SNMP_MIB_SOURCES    = $(MIB_FILES:%.mib=$(SNMP_MIB_DIR)/%.mib)
+NETSNMP_MIB_SOURCES = $(NETSNMP_MIB_FILES:%.mib=$(NETSNMP_MIB_DIR)/%.mib)
 
-MIB_TARGETS = \
+SNMP_MIB_TARGETS = \
 	$(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.bin) \
 	$(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.hrl)
+NETSNMP_MIB_TARGETS = \
+	$(NETSNMP_MIB_FILES:%.mib=$(NETSNMP_BIN_TARGET_DIR)/%.bin) \
+	$(NETSNMP_MIB_FILES:%.mib=$(NETSNMP_BIN_TARGET_DIR)/%.hrl)
+MIB_TARGETS = \
+	$(SNMP_MIB_TARGETS) \
+	$(NETSNMP_MIB_TARGETS)
+
 ERL_TARGETS = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
 
 TEST_SERVER_TARGETS = $(TEST_SERVER_MODULES:%=$(EBIN)/%.$(EMULATOR))
@@ -175,6 +186,12 @@ $(SNMP_BIN_TARGET_DIR)/%.bin: $(SNMP_MIB_DIR)/%.mib
 $(SNMP_BIN_TARGET_DIR)/%.hrl: $(SNMP_BIN_TARGET_DIR)/%.bin
 	$(ERLC) $(ERL_SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
 
+$(NETSNMP_BIN_TARGET_DIR)/%.hrl: $(NETSNMP_BIN_TARGET_DIR)/%.bin
+	$(ERLC) $(ERL_SNMP_FLAGS) -o $(NETSNMP_BIN_TARGET_DIR) $<
+
+$(NETSNMP_BIN_TARGET_DIR)/%.bin: $(NETSNMP_MIB_DIR)/%.mib
+	$(ERLC) $(ERL_SNMP_FLAGS) -o $(NETSNMP_MIB_DIR) $<
+
 
 # ----------------------------------------------------
 # Targets
@@ -244,26 +261,34 @@ release_docs_spec:
 
 
 info:
-	@echo "SNMP_DEBUG        = $(SNMP_DEBUG)"
-	@echo "SNMP_FLAGS        = $(SNMP_FLAGS)"
+	@echo "SNMP_DEBUG             = $(SNMP_DEBUG)"
+	@echo "SNMP_FLAGS             = $(SNMP_FLAGS)"
+	@echo ""
+	@echo "SNMP_MIB_DIR           = $(SNMP_MIB_DIR)"
+	@echo "NETSNMP_MIB_DIR        = $(NETSNMP_MIB_DIR)"
+	@echo ""
+	@echo "SNMP_BIN_TARGET_DIR    = $(SNMP_BIN_TARGET_DIR)"
+	@echo "NETSNMP_BIN_TARGET_DIR = $(NETSNMP_BIN_TARGET_DIR)"
+	@echo ""
+	@echo "SNMP_MIB_SOURCES    = $(SNMP_MIB_SOURCES)"
+	@echo "NETSNMP_MIB_SOURCES = $(NETSNMP_MIB_SOURCES)"
+	@echo ""
+	@echo "MIB_TARGETS         = $(MIB_TARGETS)"
 	@echo ""
-	@echo "SNMP_MIB_DIR      = $(SNMP_MIB_DIR)"
-	@echo "MIB_SOURCE        = $(MIB_SOURCE)"
-	@echo "MIB_TARGETS       = $(MIB_TARGETS)"
-	@echo "SNMP_MIB_FLAGS    = $(SNMP_MIB_FLAGS)"
+	@echo "SNMP_MIB_FLAGS      = $(SNMP_MIB_FLAGS)"
 	@echo ""
-	@echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
+	@echo "ERL_COMPILE_FLAGS   = $(ERL_COMPILE_FLAGS)"
 	@echo ""
-	@echo "RELSYSDIR         = "$(RELSYSDIR)""
+	@echo "RELSYSDIR           = "$(RELSYSDIR)""
 	@echo ""
-	@echo "SOURCE            = $(SOURCE)"
+	@echo "SOURCE              = $(SOURCE)"
 	@echo ""
-	@echo "TARGET_FILES      = $(TARGET_FILES)"
+	@echo "TARGET_FILES        = $(TARGET_FILES)"
 	@echo ""
-	@echo "EMAKEFILE         = $(EMAKEFILE)"
-	@echo "MAKE_EMAKE        = $(MAKE_EMAKE)"
-	@echo "BUILDTARGET       = $(BUILDTARGET)"
-	@echo "RELTEST_FILES     = $(RELTEST_FILES)"
+	@echo "EMAKEFILE           = $(EMAKEFILE)"
+	@echo "MAKE_EMAKE          = $(MAKE_EMAKE)"
+	@echo "BUILDTARGET         = $(BUILDTARGET)"
+	@echo "RELTEST_FILES       = $(RELTEST_FILES)"
 	@echo ""
 
 
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 0cee86bd48..6074865d5c 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -83,5 +83,8 @@ MIB_FILES = \
 	Test2.mib \
 	Test3.mib
 
+NETSNMP_MIB_FILES = \
+	OTP-C64-MIB.mib
+
 SPECS = snmp.spec
 
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index 103e73ea80..77c859f48e 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -43,8 +43,10 @@
         ]).
 
 -include("snmp_test_lib.hrl").
+-include("snmp_to_snmpnet_SUITE_data/OTP-C64-MIB.hrl").
 -include_lib("common_test/include/ct.hrl").
 -include_lib("snmp/include/STANDARD-MIB.hrl").
+-include_lib("snmp/include/snmp_types.hrl").
 
 -define(AGENT_ENGINE_ID, "ErlangSnmpAgent").
 -define(MANAGER_ENGINE_ID, "ErlangSnmpManager").
@@ -54,7 +56,26 @@
 
 expected(?sysDescr_instance = Oid, get) ->
     OidStr = oid_str(Oid),
-    lists:flatten([OidStr | " = STRING: \"Erlang SNMP agent\""]).
+    lists:flatten([OidStr | " = STRING: \"Erlang SNMP agent\""]);
+expected(?otpC64Num1_instance = Oid, get) ->
+    OidStr = oid_str(Oid),
+    ?F("~s = Counter64: ~w", [OidStr, ?default_otpC64Num1]);
+expected(?otpC64Num2_instance = Oid, get) ->
+    OidStr = oid_str(Oid),
+    ?F("~s = Counter64: ~w", [OidStr, ?default_otpC64Num2]);
+expected(?otpC64Num3_instance = Oid, get) ->
+    OidStr = oid_str(Oid),
+    ?F("~s = Counter64: ~w", [OidStr, ?default_otpC64Num3]);
+expected(?otpC64Num4_instance = Oid, get) ->
+    OidStr = oid_str(Oid),
+    ?F("~s = Counter64: ~w", [OidStr, ?default_otpC64Num4]).
+
+oids() ->
+    [?sysDescr_instance,
+     ?otpC64Num1_instance,
+     ?otpC64Num2_instance,
+     ?otpC64Num3_instance,
+     ?otpC64Num4_instance].
 
 
 %%--------------------------------------------------------------------
@@ -147,11 +168,17 @@ init_per_suite(Config0) ->
 
                 Config2 when is_list(Config2) ->
                     snmp_test_sys_monitor:start(),
+
+                    MibDir    = ?LIB:lookup(data_dir, Config2),
+                    StdMibDir = join(code:lib_dir(snmp), "mibs"),
+                    
+                    Config3 = [{mib_dir,     MibDir},
+                               {std_mib_dir, StdMibDir} | Config2],
                     
                     ?IPRINT("init_per_suite -> end when"
-                            "~n      Config: ~p", [Config2]),
+                            "~n      Config: ~p", [Config3]),
 
-                    Config2
+                    Config3
             end
     end.
 
@@ -343,7 +370,7 @@ find_executable(Exec, Config) ->
 find_sys_executable(_Exec, ExecStr, [], _Config) ->
     {skip, ExecStr ++ " not found"};
 find_sys_executable(Exec, ExecStr, [Dir | Dirs], Config) ->
-    case os:find_executable(filename:join(["/" | Dir] ++ [ExecStr])) of
+    case os:find_executable(join(["/" | Dir] ++ [ExecStr])) of
 	false ->
 	    find_sys_executable(Exec, ExecStr, Dirs, Config);
 	Path ->
@@ -351,9 +378,22 @@ find_sys_executable(Exec, ExecStr, [Dir | Dirs], Config) ->
     end.
 
 start_agent(Config) ->
-    ok = application:load(snmp),
-    ok = application:set_env(snmp, agent, agent_app_env(Config)),
-    ok = application:start(snmp).
+    Dir = ?config(mib_dir, Config),
+    ok  = application:load(snmp),
+    ok  = application:set_env(snmp, agent, agent_app_env(Config)),
+    ok  = application:start(snmp),
+    Mibs = ["OTP-C64-MIB"],
+    load_mibs(Dir, Mibs),
+    ok.
+
+load_mibs(Dir, Mibs) ->
+    lists:foreach(fun(Mib) -> load_mib(Dir, Mib) end, Mibs).
+
+load_mib(Dir, Mib) ->
+    _   = snmpa:unload_mib(snmp_master_agent, Mib),
+    ok  = snmpa:load_mib(snmp_master_agent, join(Dir, Mib)).
+    
+                           
 
 %% stop_agent(_Config) ->
 %%     case application:stop(snmp) of
@@ -400,23 +440,10 @@ erlang_agent_netsnmp_get() ->
 erlang_agent_netsnmp_get(Config) when is_list(Config) ->
     Transports = ?config(transports, Config),
     start_agent(Config),
-    Oid = ?sysDescr_instance,
-    Expected = expected(Oid, get),
+    Oids = oids(),
     try
         begin
-            [case snmpget(Oid, Transport, Config) of
-                 Expected ->
-                     ct:pal("Received expected", []),
-                     ok;
-                 "Timeout: " ++ Rest ->
-                     ct:pal("Received unexpected timeout: "
-                            "~n   ~s", [Rest]),
-                     throw({skip, Rest});
-                 Any ->
-                     ct:pal("Received unexpected response: "
-                            "~n   ~p", [Any]),
-                     exit({unexpected, Any})
-             end || Transport <- Transports],
+            [do_get(Oid, Transports, Config) || Oid <- Oids],
             ok
         end
     catch
@@ -424,6 +451,27 @@ erlang_agent_netsnmp_get(Config) when is_list(Config) ->
             SKIP
     end.
 
+do_get(Oid, Transports, Config) ->
+    Expected = expected(Oid, get),
+    ct:pal("Try get ~p"
+           "~n   Expected: ~p", [Oid, Expected]),
+    Get = fun(Transport) ->
+                  case snmpget(Oid, Transport, Config) of
+                      Expected ->
+                          ct:pal("Received expected", []),
+                          ok;
+                      "Timeout: " ++ Rest ->
+                          ct:pal("Received unexpected timeout: "
+                                 "~n   ~s", [Rest]),
+                          throw({skip, Rest});
+                      Any ->
+                          ct:pal("Received unexpected response: "
+                                 "~n   ~p", [Any]),
+                          exit({unexpected, Any})
+                  end
+          end,
+    lists:foreach(Get, Transports).
+
 
 %%--------------------------------------------------------------------
 erlang_manager_netsnmp_get() ->
@@ -450,18 +498,54 @@ erlang_manager_netsnmp_get(Config) when is_list(Config) ->
             Results =
                 [snmp_manager_user:sync_get2(
                    TargetName++domain_suffix(Domain),
-                   [?sysDescr_instance], [])
+                   oids(), [])
                  || {Domain, _} <- Transports],
             ct:pal("sync_get -> ~p", [Results]),
             snmp_manager_user:stop(),
             stop_program(ProgHandle),
-            [{ok,
-              {noError, 0,
-               [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
-              _} = R || R <- Results],
+            [verify_result(R) || R <- Results],
             ok
     end.
 
+verify_result({ok, {noError, 0, VBs}, _}) ->
+    verify_varbinds(VBs);
+verify_result(Result) ->
+    exit({invalid_result, Result}).
+
+verify_varbinds([] = _VBs) ->
+    ok;
+verify_varbinds([VB | VBs]) ->
+    verify_varbind(VB),
+    verify_varbinds(VBs).
+
+verify_varbind(#varbind{oid          = Oid,
+                        variabletype = Type,
+                        value        = Value}) ->
+    verify_oid(Oid, Type, Value).
+
+verify_oid(?sysDescr_instance = Oid, 'OCTET STRING', "Net-SNMP agent") ->
+    ct:pal("oid verification success for ~p", [Oid]),
+    ok;
+verify_oid(?otpC64Num1_instance = Oid, 'Counter64', ?default_otpC64Num1) ->
+    ct:pal("oid verification success for ~p", [Oid]),
+    ok;
+verify_oid(?otpC64Num2_instance = Oid, 'Counter64', ?default_otpC64Num2) ->
+    ct:pal("oid verification success for ~p", [Oid]),
+    ok;
+verify_oid(?otpC64Num3_instance = Oid, 'Counter64', ?default_otpC64Num3) ->
+    ct:pal("oid verification success for ~p", [Oid]),
+    ok;
+verify_oid(?otpC64Num4_instance = Oid, 'Counter64', ?default_otpC64Num4) ->
+    ct:pal("oid verification success for ~p", [Oid]),
+    ok;
+verify_oid(Oid, 'NULL', noSuchObject = Value) ->
+    %% This means we where unable to load the proper MIBs
+    ct:pal("oid verification failed for ~p => ~p => IGNORE", [Oid, Value]),
+    ok;
+verify_oid(Oid, Type, Value) ->
+    ct:pal("oid verification failed: ~p => ~p", [Oid, Value]),
+    exit({invalid_vb, Oid, Type, Value}).
+
 
 %%--------------------------------------------------------------------
 erlang_agent_netsnmp_inform() ->
@@ -472,7 +556,7 @@ erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
     Mib = "TestTrapv2",
 
     start_agent(Config),
-    ok = snmpa:load_mib(snmp_master_agent, filename:join(DataDir, Mib)),
+    ok = snmpa:load_mib(snmp_master_agent, join(DataDir, Mib)),
 
     case start_snmptrapd(Mib, Config) of
         {skip, _} = SKIP ->
@@ -512,6 +596,7 @@ erlang_agent_netsnmp_inform_responses([Address | Addresses]) ->
 %%--------------------------------------------------------------------
 
 snmpget(Oid, Transport, Config) ->
+    ct:pal("Try get ~p on ~p~n", [Oid, Transport]),
     Versions = ?config(snmp_versions, Config),
 
     Args =
@@ -531,7 +616,7 @@ snmpget(Oid, Transport, Config) ->
 
 start_snmptrapd(Mibs, Config) ->
     DataDir = ?config(data_dir, Config),
-    MibDir = filename:join(code:lib_dir(snmp), "mibs"),
+    MibDir = join(code:lib_dir(snmp), "mibs"),
     Targets = ?config(targets, Config),
     SnmptrapdArgs =
 	["-f", "-Lo", "-C",
@@ -543,8 +628,10 @@ start_snmptrapd(Mibs, Config) ->
     start_program(snmptrapd, SnmptrapdArgs, StartCheckMP, Config).
 
 start_snmpd(Community, SysDescr, Config) ->
-    DataDir = ?config(data_dir, Config),
-    Targets = ?config(targets, Config),
+    DataDir    = ?config(data_dir, Config),
+    MibDir     = ?config(mib_dir, Config),
+    StdMibDir  = ?config(std_mib_dir, Config),
+    Targets    = ?config(targets, Config),
     Transports = ?config(transports, Config),
     Port = mk_port_number(),
     CommunityArgs =
@@ -552,12 +639,18 @@ start_snmpd(Community, SysDescr, Config) ->
 	 ++Community++" "++inet_parse:ntoa(Ip)
 	 || {Domain, {Ip, _}} <- Targets],
 
+    Mibs    = "SNMPv2-SMI" ++
+        ":" ++ "OTP-REG" ++
+        ":" "OTP-C64-MIB",
+    MibDirs = StdMibDir ++ ":" ++ MibDir,
+
     SnmpdArgs =
         ["-f", "-r", %"-Dverbose",
-         "-c", filename:join(DataDir, "snmpd.conf"),
+         "-c", join(DataDir, "snmpd.conf"),
          "-C",
          "-Lo",
-	 "-m", ":",
+         "-m", Mibs,
+         "-M", MibDirs,
 	 "--sysDescr="++SysDescr,
 	 "--agentXSocket=tcp:localhost:"++integer_to_list(Port)]
 	++ CommunityArgs
@@ -565,11 +658,20 @@ start_snmpd(Community, SysDescr, Config) ->
     {ok, StartCheckMP} = re:compile("NET-SNMP version ", [anchored]),
     start_program(snmpd, SnmpdArgs, StartCheckMP, Config).
 
+%% Debug function: It simple makes printing the args string simple
+prep([]) ->
+    "";
+prep([Arg]) when is_list(Arg) ->
+    Arg;
+prep([Arg|Args]) ->
+    Arg ++ " " ++ prep(Args).
+
 start_program(Prog, Args, StartCheckMP, Config) ->
-    ct:pal("Starting program: ~w ~p", [Prog, Args]),
+    ct:pal("Starting program: ~w ~p:"
+           "~n~s", [Prog, Args, ?F("~w ~s", [Prog, prep(Args)])]),
     Path = ?config(Prog, Config),
     DataDir = ?config(data_dir, Config),
-    StartWrapper = filename:join(DataDir, "start_stop_wrapper"),
+    StartWrapper = join(DataDir, "start_stop_wrapper"),
     Parent = self(),
     %% process_flag(trap_exit, true),
     {Pid, Mon} =
@@ -784,3 +886,8 @@ mk_port_number() ->
     ok = gen_udp:close(Socket),
     PortNum.
 
+join(List) ->
+    filename:join(List).
+join(Dir, File) ->
+    filename:join(Dir, File).
+
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE_data/OTP-C64-MIB.mib b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/OTP-C64-MIB.mib
new file mode 100644
index 0000000000..2769c9a2ab
--- /dev/null
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/OTP-C64-MIB.mib
@@ -0,0 +1,102 @@
+-- %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%
+
+--
+-- Test mib for Counter64 tests
+--
+
+OTP-C64-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+    otpExpr
+        FROM OTP-REG
+    MODULE-IDENTITY, Counter64
+        FROM SNMPv2-SMI
+    OBJECT-GROUP
+        FROM SNMPv2-CONF;
+
+
+otpC64MIB MODULE-IDENTITY
+    LAST-UPDATED "202410080000Z"
+    ORGANIZATION "Erlang/OTP"
+    CONTACT-INFO
+        "flipp@flopp.org"
+     DESCRIPTION
+         "Initial version of this MIB module."
+     ::= { otpExpr 42 }
+
+
+otpC64Objects     OBJECT IDENTIFIER ::= { otpC64MIB 1 }
+
+otpC64Conformance OBJECT IDENTIFIER ::= { otpC64MIB 2 }
+
+otpC64Groups      OBJECT IDENTIFIER ::= { otpC64Conformance 1}
+
+otpC64            OBJECT IDENTIFIER ::= { otpC64Objects 1 }
+
+otpC64Num1 OBJECT-TYPE
+    SYNTAX       Counter64
+    MAX-ACCESS   read-only
+    STATUS       current
+    DESCRIPTION
+        "This object shows nothing..."
+   DEFVAL { 18446744073709551615 }
+    ::= { otpC64 1 }
+
+otpC64Num2 OBJECT-TYPE
+    SYNTAX       Counter64
+    MAX-ACCESS   read-only
+    STATUS       current
+    DESCRIPTION
+        "This object shows nothing..."
+   DEFVAL { 9223372036854775807 }
+    ::= { otpC64 2 }
+
+otpC64Num3 OBJECT-TYPE
+    SYNTAX       Counter64
+    MAX-ACCESS   read-only
+    STATUS       current
+    DESCRIPTION
+        "This object shows nothing..."
+   DEFVAL { 9223372036854775808 }
+    ::= { otpC64 3 }
+
+otpC64Num4 OBJECT-TYPE
+    SYNTAX       Counter64
+    MAX-ACCESS   read-only
+    STATUS       current
+    DESCRIPTION
+        "This object shows nothing..."
+   DEFVAL { 9223372036854775809 }
+    ::= { otpC64 4 }
+
+otpC64Numbers    OBJECT-GROUP
+    OBJECTS {
+              otpC64Num1,
+              otpC64Num2,
+              otpC64Num3,
+              otpC64Num4
+            }
+    STATUS  current
+    DESCRIPTION
+            "The collection of fake counter objects."
+    ::= { otpC64Groups 1 }
+
+END
-- 
2.43.0

openSUSE Build Service is sponsored by