test_netlink: Add basic request test

This adds a basic request / response test for netlink by faking out the
enumeration of network interfaces.

Change-Id: I6a2d4f8e162bb127976a6ea8721f663bce662f18
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/mock_syscall.cpp b/test/mock_syscall.cpp
index 280c74d..421dbfe 100644
--- a/test/mock_syscall.cpp
+++ b/test/mock_syscall.cpp
@@ -1,3 +1,5 @@
+#include "util.hpp"
+
 #include <arpa/inet.h>
 #include <dlfcn.h>
 #include <ifaddrs.h>
@@ -123,6 +125,37 @@
     }
 }
 
+ssize_t sendmsg_link_dump(std::queue<std::string>& msgs, std::string_view in)
+{
+    const ssize_t ret = in.size();
+    const auto& hdrin = phosphor::copyFrom<nlmsghdr>(in);
+    if (hdrin.nlmsg_type != RTM_GETLINK)
+    {
+        return 0;
+    }
+
+    for (const auto& [name, idx] : mock_if_nametoindex)
+    {
+        ifinfomsg info{};
+        info.ifi_index = idx;
+        nlmsghdr hdr{};
+        hdr.nlmsg_len = NLMSG_LENGTH(sizeof(info));
+        hdr.nlmsg_type = RTM_NEWLINK;
+        hdr.nlmsg_flags = NLM_F_MULTI;
+        auto& out = msgs.emplace(hdr.nlmsg_len, '\0');
+        memcpy(out.data(), &hdr, sizeof(hdr));
+        memcpy(NLMSG_DATA(out.data()), &info, sizeof(info));
+    }
+
+    nlmsghdr hdr{};
+    hdr.nlmsg_len = NLMSG_LENGTH(0);
+    hdr.nlmsg_type = NLMSG_DONE;
+    hdr.nlmsg_flags = NLM_F_MULTI;
+    auto& out = msgs.emplace(hdr.nlmsg_len, '\0');
+    memcpy(out.data(), &hdr, sizeof(hdr));
+    return ret;
+}
+
 ssize_t sendmsg_ack(std::queue<std::string>& msgs, std::string_view in)
 {
     nlmsgerr ack{};
@@ -249,6 +282,12 @@
     std::string_view iov(reinterpret_cast<char*>(msg->msg_iov[0].iov_base),
                          msg->msg_iov[0].iov_len);
 
+    ret = sendmsg_link_dump(msgs, iov);
+    if (ret != 0)
+    {
+        return ret;
+    }
+
     ret = sendmsg_ack(msgs, iov);
     if (ret != 0)
     {
diff --git a/test/test_netlink.cpp b/test/test_netlink.cpp
index 41cd1ca..8d20c39 100644
--- a/test/test_netlink.cpp
+++ b/test/test_netlink.cpp
@@ -286,6 +286,46 @@
     EXPECT_EQ(0, memcmp(&nextbuf, data.data(), sizeof(nextbuf)));
 }
 
+class PerformRequest : public testing::Test
+{
+  public:
+    void doLinkDump(size_t ifs)
+    {
+        mock_clear();
+        for (size_t i = 0; i < ifs; ++i)
+        {
+            mock_addIF("eth" + std::to_string(i), 1 + i);
+        }
+
+        size_t cbCalls = 0;
+        auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
+        ifinfomsg msg{};
+        netlink::performRequest(NETLINK_ROUTE, RTM_GETLINK, NLM_F_DUMP, msg,
+                                cb);
+        EXPECT_EQ(ifs, cbCalls);
+    }
+};
+
+TEST_F(PerformRequest, NoResponse)
+{
+    doLinkDump(0);
+}
+
+TEST_F(PerformRequest, SingleResponse)
+{
+    doLinkDump(1);
+}
+
+TEST_F(PerformRequest, MultiResponse)
+{
+    doLinkDump(3);
+}
+
+TEST_F(PerformRequest, MultiMsg)
+{
+    doLinkDump(1000);
+}
+
 } // namespace netlink
 } // namespace network
 } // namespace phosphor