test/ethernet_interface: Improve syscall test coverage

Change-Id: Ia71a030f2e2e19f2cc191992929ef08d0fa917c2
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index 498cab8..529bb2a 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -141,7 +141,17 @@
     // would be same as parent interface.
     if (intfName.find(".") == std::string::npos)
     {
-        MacAddressIntf::macAddress(getMACAddress(intfName));
+        try
+        {
+            MacAddressIntf::macAddress(getMACAddress(intfName));
+        }
+        catch (const std::exception& e)
+        {
+            auto msg =
+                fmt::format("Failed to get MAC for {}: {}", intfName, e.what());
+            log<level::ERR>(msg.c_str(),
+                            entry("INTERFACE=%s", intfName.c_str()));
+        }
     }
     EthernetInterfaceIntf::ntpServers(
         config.map.getValueStrings("Network", "NTP"));
diff --git a/test/mock_ethernet_interface.hpp b/test/mock_ethernet_interface.hpp
index 5e21170..1f72486 100644
--- a/test/mock_ethernet_interface.hpp
+++ b/test/mock_ethernet_interface.hpp
@@ -1,7 +1,5 @@
 #pragma once
-
 #include "ethernet_interface.hpp"
-#include "mock_syscall.hpp"
 
 #include <gmock/gmock.h>
 
@@ -12,10 +10,9 @@
 class MockEthernetInterface : public EthernetInterface
 {
   public:
-    MockEthernetInterface(sdbusplus::bus_t& bus, const std::string& objPath,
-                          const config::Parser& config, Manager& parent,
-                          bool emitSignal) :
-        EthernetInterface(bus, objPath, config, parent, emitSignal,
+    template <typename... Args>
+    MockEthernetInterface(Args&&... args) :
+        EthernetInterface(std::forward<Args>(args)..., /*emitSignal=*/false,
                           /*nicEnabled=*/true)
     {
     }
diff --git a/test/mock_network_manager.hpp b/test/mock_network_manager.hpp
index af26771..9286d0c 100644
--- a/test/mock_network_manager.hpp
+++ b/test/mock_network_manager.hpp
@@ -1,4 +1,5 @@
 #pragma once
+#include "config_parser.hpp"
 #include "mock_ethernet_interface.hpp"
 #include "network_manager.hpp"
 #include "util.hpp"
@@ -34,7 +35,7 @@
             objPath /= interface;
             config::Parser config(config::pathForIntfConf(confDir, interface));
             auto intf = std::make_unique<MockEthernetInterface>(
-                bus, objPath.string(), config, *this, true);
+                bus, objPath.string(), config, *this);
             intf->createIPAddressObjects();
             intf->createStaticNeighborObjects();
             intf->loadNameServers(config);
diff --git a/test/mock_syscall.cpp b/test/mock_syscall.cpp
index e4101a3..349a79a 100644
--- a/test/mock_syscall.cpp
+++ b/test/mock_syscall.cpp
@@ -49,34 +49,40 @@
 
 std::map<int, std::queue<std::string>> mock_rtnetlinks;
 
-std::map<std::string, int> mock_if_nametoindex;
+struct MockInfo
+{
+    unsigned idx;
+    unsigned flags;
+    std::optional<ether_addr> mac;
+    std::optional<unsigned> mtu;
+};
+
+std::map<std::string, MockInfo> mock_if;
 std::map<int, std::string> mock_if_indextoname;
-std::map<std::string, ether_addr> mock_macs;
 
 void mock_clear()
 {
     mock_ifaddrs = nullptr;
     ifaddr_count = 0;
     mock_rtnetlinks.clear();
-    mock_if_nametoindex.clear();
+    mock_if.clear();
     mock_if_indextoname.clear();
-    mock_macs.clear();
 }
 
-void mock_addIF(const std::string& name, int idx, const ether_addr& mac)
+void mock_addIF(const std::string& name, unsigned idx, unsigned flags,
+                std::optional<ether_addr> mac, std::optional<unsigned> mtu)
 {
     if (idx == 0)
     {
         throw std::invalid_argument("Bad interface index");
     }
 
-    mock_if_nametoindex[name] = idx;
-    mock_if_indextoname[idx] = name;
-    mock_macs[name] = mac;
+    mock_if.emplace(
+        name, MockInfo{.idx = idx, .flags = flags, .mac = mac, .mtu = mtu});
+    mock_if_indextoname.emplace(idx, name);
 }
 
-void mock_addIP(const char* name, const char* addr, const char* mask,
-                unsigned int flags)
+void mock_addIP(const char* name, const char* addr, const char* mask)
 {
     struct ifaddrs* ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
 
@@ -95,7 +101,7 @@
 
     ifaddr->ifa_next = nullptr;
     ifaddr->ifa_name = const_cast<char*>(name);
-    ifaddr->ifa_flags = flags;
+    ifaddr->ifa_flags = 0;
     ifaddr->ifa_addr = reinterpret_cast<struct sockaddr*>(in);
     ifaddr->ifa_netmask = reinterpret_cast<struct sockaddr*>(mask_in);
     ifaddr->ifa_data = nullptr;
@@ -135,10 +141,11 @@
         return 0;
     }
 
-    for (const auto& [name, idx] : mock_if_nametoindex)
+    for (const auto& [name, i] : mock_if)
     {
         ifinfomsg info{};
-        info.ifi_index = idx;
+        info.ifi_index = i.idx;
+        info.ifi_flags = i.flags;
         nlmsghdr hdr{};
         hdr.nlmsg_len = NLMSG_LENGTH(sizeof(info));
         hdr.nlmsg_type = RTM_NEWLINK;
@@ -181,13 +188,13 @@
 
 unsigned if_nametoindex(const char* ifname)
 {
-    auto it = mock_if_nametoindex.find(ifname);
-    if (it == mock_if_nametoindex.end())
+    auto it = mock_if.find(ifname);
+    if (it == mock_if.end())
     {
         errno = ENXIO;
         return 0;
     }
-    return it->second;
+    return it->second.idx;
 }
 
 char* if_indextoname(unsigned ifindex, char* ifname)
@@ -208,16 +215,49 @@
     void* data = va_arg(vl, void*);
     va_end(vl);
 
+    auto req = reinterpret_cast<ifreq*>(data);
     if (request == SIOCGIFHWADDR)
     {
-        auto req = reinterpret_cast<ifreq*>(data);
-        auto it = mock_macs.find(req->ifr_name);
-        if (it == mock_macs.end())
+        auto it = mock_if.find(req->ifr_name);
+        if (it == mock_if.end())
         {
             errno = ENXIO;
             return -1;
         }
-        std::memcpy(req->ifr_hwaddr.sa_data, &it->second, sizeof(it->second));
+        if (!it->second.mac)
+        {
+            errno = EOPNOTSUPP;
+            return -1;
+        }
+        std::memcpy(req->ifr_hwaddr.sa_data, &*it->second.mac,
+                    sizeof(*it->second.mac));
+        return 0;
+    }
+    else if (request == SIOCGIFFLAGS)
+    {
+        auto it = mock_if.find(req->ifr_name);
+        if (it == mock_if.end())
+        {
+            errno = ENXIO;
+            return -1;
+        }
+        req->ifr_flags = it->second.flags;
+        return 0;
+    }
+    else if (request == SIOCGIFMTU)
+    {
+        auto it = mock_if.find(req->ifr_name);
+        if (it == mock_if.end())
+        {
+            errno = ENXIO;
+            return -1;
+        }
+        if (!it->second.mtu)
+        {
+            errno = EOPNOTSUPP;
+            return -1;
+        }
+        req->ifr_mtu = *it->second.mtu;
         return 0;
     }
 
diff --git a/test/mock_syscall.hpp b/test/mock_syscall.hpp
index 74a693e..8d51e0f 100644
--- a/test/mock_syscall.hpp
+++ b/test/mock_syscall.hpp
@@ -1,6 +1,7 @@
 #pragma once
 #include <net/ethernet.h>
 
+#include <optional>
 #include <string>
 
 /** @brief Clears out the interfaces and IPs configured for mocking
@@ -15,8 +16,7 @@
  *  @param[in] flags - Interface flags.
  */
 
-void mock_addIP(const char* name, const char* addr, const char* mask,
-                unsigned int flags);
+void mock_addIP(const char* name, const char* addr, const char* mask);
 
 /** @brief Adds an address string to index mapping and MAC mapping
  *
@@ -24,5 +24,6 @@
  *  @param[in] idx  - Interface index
  *  @param[in] mac  - Interface MAC address
  */
-void mock_addIF(const std::string& name, int idx,
-                const ether_addr& mac = ether_addr{});
+void mock_addIF(const std::string& name, unsigned idx, unsigned flags = 0,
+                std::optional<ether_addr> mac = std::nullopt,
+                std::optional<unsigned> mtu = std::nullopt);
diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp
index 497eaa0..ad30c0a 100644
--- a/test/test_ethernet_interface.cpp
+++ b/test/test_ethernet_interface.cpp
@@ -39,15 +39,13 @@
     {
     }
 
-    static constexpr ether_addr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
-
     static MockEthernetInterface makeInterface(sdbusplus::bus_t& bus,
                                                MockManager& manager)
     {
         mock_clear();
-        mock_addIF("test0", 1, mac);
+        mock_addIF("test0", /*idx=*/1);
         return {bus, "/xyz/openbmc_test/network/test0", config::Parser(),
-                manager, true};
+                manager};
     }
 
     int countIPObjects()
@@ -92,10 +90,28 @@
     }
 };
 
+TEST_F(TestEthernetInterface, Fields)
+{
+    EXPECT_EQ(0, interface.mtu());
+    EXPECT_EQ("", interface.macAddress());
+    EXPECT_FALSE(interface.linkUp());
+
+    constexpr unsigned idx = 2;
+    constexpr ether_addr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    constexpr unsigned mtu = 150;
+
+    mock_addIF("test1", idx, IFF_RUNNING, mac, mtu);
+    MockEthernetInterface intf(bus, "/xyz/openbmc_test/network/test1",
+                               config::Parser(), manager);
+
+    EXPECT_EQ(mtu, intf.mtu());
+    EXPECT_EQ(mac_address::toString(mac), intf.macAddress());
+    EXPECT_TRUE(intf.linkUp());
+}
+
 TEST_F(TestEthernetInterface, NoIPaddress)
 {
     EXPECT_EQ(countIPObjects(), 0);
-    EXPECT_EQ(mac_address::toString(mac), interface.macAddress());
 }
 
 TEST_F(TestEthernetInterface, AddIPAddress)
diff --git a/test/test_netlink.cpp b/test/test_netlink.cpp
index b3538f2..71be8e9 100644
--- a/test/test_netlink.cpp
+++ b/test/test_netlink.cpp
@@ -298,7 +298,7 @@
         mock_clear();
         for (size_t i = 0; i < ifs; ++i)
         {
-            mock_addIF("eth" + std::to_string(i), 1 + i);
+            mock_addIF(fmt::format("eth{}", i), /*idx=*/1 + i);
         }
 
         size_t cbCalls = 0;
diff --git a/test/test_network_manager.cpp b/test/test_network_manager.cpp
index 3d4cee8..a607bb7 100644
--- a/test/test_network_manager.cpp
+++ b/test/test_network_manager.cpp
@@ -19,6 +19,8 @@
 namespace network
 {
 
+using ::testing::Key;
+using ::testing::UnorderedElementsAre;
 namespace fs = std::filesystem;
 
 class TestNetworkManager : public stdplus::gtest::TestWithTmp
@@ -50,15 +52,13 @@
     mock_clear();
 
     // Adds the following ip in the getifaddrs list.
-    mock_addIF("igb1", 2);
-    mock_addIP("igb1", "192.0.2.3", "255.255.255.128", IFF_UP | IFF_RUNNING);
+    mock_addIF("igb1", /*idx=*/2);
+    mock_addIP("igb1", "192.0.2.3", "255.255.255.128");
 
     // Now create the interfaces which will call the mocked getifaddrs
     // which returns the above interface detail.
     createInterfaces();
-    EXPECT_EQ(1, manager.getInterfaces().size());
-    EXPECT_NE(manager.getInterfaces().end(),
-              manager.getInterfaces().find("igb1"));
+    EXPECT_THAT(manager.getInterfaces(), UnorderedElementsAre(Key("igb1")));
 }
 
 // getifaddrs returns two interfaces.
@@ -66,18 +66,14 @@
 {
     mock_clear();
 
-    mock_addIF("igb0", 1);
-    mock_addIP("igb0", "192.0.2.2", "255.255.255.128", IFF_UP | IFF_RUNNING);
-
-    mock_addIF("igb1", 2);
-    mock_addIP("igb1", "192.0.2.3", "255.255.255.128", IFF_UP | IFF_RUNNING);
+    mock_addIF("igb0", /*idx=*/1);
+    mock_addIP("igb0", "192.0.2.2", "255.255.255.128");
+    mock_addIF("igb1", /*idx=*/2);
+    mock_addIP("igb1", "192.0.2.3", "255.255.255.128");
 
     createInterfaces();
-    EXPECT_EQ(2, manager.getInterfaces().size());
-    EXPECT_NE(manager.getInterfaces().end(),
-              manager.getInterfaces().find("igb0"));
-    EXPECT_NE(manager.getInterfaces().end(),
-              manager.getInterfaces().find("igb1"));
+    EXPECT_THAT(manager.getInterfaces(),
+                UnorderedElementsAre(Key("igb0"), Key("igb1")));
 }
 } // namespace network
 } // namespace phosphor
diff --git a/test/test_rtnetlink.cpp b/test/test_rtnetlink.cpp
index 21aaca3..b11100f 100644
--- a/test/test_rtnetlink.cpp
+++ b/test/test_rtnetlink.cpp
@@ -57,8 +57,8 @@
     using namespace std::chrono;
     mock_clear();
     // Adds the following ip in the getifaddrs list.
-    mock_addIF("igb5", 6);
-    mock_addIP("igb5", "127.0.0.1", "255.255.255.128", IFF_UP | IFF_RUNNING);
+    mock_addIF("igb5", /*idx=*/6);
+    mock_addIP("igb5", "127.0.0.1", "255.255.255.128");
     constexpr auto BUFSIZE = 4096;
     std::array<char, BUFSIZE> msgBuf = {0};
 
diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp
index c4734b1..9c3a1ea 100644
--- a/test/test_vlan_interface.cpp
+++ b/test/test_vlan_interface.cpp
@@ -40,13 +40,13 @@
                                            MockManager& manager)
     {
         mock_clear();
-        mock_addIF("test0", 1);
+        mock_addIF("test0", /*idx=*/1);
         return {bus,
                 "/xyz/openbmc_test/network/test0",
                 config::Parser(),
                 manager,
-                false,
-                true};
+                /*emitSignals=*/false,
+                /*nicEnabled=*/true};
     }
 
     void createVlan(VlanId id)