Add function to write DNS entries

Added function to write DNS entries to specified file
Also, added test case

Change-Id: I64250c7ee3cf7db3e7f8b5cf1669c7b4a7738637
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index eac5692..e2f2fcf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,7 +22,8 @@
 		dhcp_configuration.hpp \
 		vlan_interface.hpp \
 		rtnetlink_server.hpp \
-		timer.hpp
+		timer.hpp \
+		dns_updater.hpp
 
 phosphor_network_manager_SOURCES = \
 		ethernet_interface.cpp \
@@ -39,7 +40,8 @@
 		dhcp_configuration.cpp \
         vlan_interface.cpp \
 		rtnetlink_server.cpp \
-		timer.cpp
+		timer.cpp \
+		dns_updater.cpp
 
 CLEANFILES = \
 		xyz/openbmc_project/Network/VLAN/Create/server.cpp \
diff --git a/dns_updater.cpp b/dns_updater.cpp
new file mode 100644
index 0000000..5c4d058
--- /dev/null
+++ b/dns_updater.cpp
@@ -0,0 +1,59 @@
+#include "config.h"
+#include "dns_updater.hpp"
+
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <fstream>
+
+namespace phosphor
+{
+namespace network
+{
+namespace dns
+{
+namespace updater
+{
+
+void processDNSEntries(const fs::path& inFile,
+                       const fs::path& outFile)
+{
+    using namespace phosphor::logging;
+    using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+    std::fstream outStream(outFile, std::fstream::out);
+    if (!outStream.is_open())
+    {
+        log<level::ERR>("Unable to open output file",
+                        entry("FILE=%s", outFile.c_str()));
+        elog<InternalFailure>();
+    }
+
+    std::fstream inStream(inFile, std::fstream::in);
+    if (!inStream.is_open())
+    {
+        log<level::ERR>("Unable to open the input file",
+                        entry("FILE=%s", inFile.c_str()));
+        elog<InternalFailure>();
+    }
+
+    outStream << "### Generated by phosphor-networkd ###\n";
+
+    for (std::string line; std::getline(inStream, line);)
+    {
+        auto index = line.find("DNS=");
+        if(index != std::string::npos)
+        {
+           auto dns = line.substr(index + 4);
+           outStream << "nameserver " << dns << "\n" ;
+        }
+    }
+    return;
+}
+
+} // namespace updater
+} // namespace dns
+} // namespace network
+} // namespace phosphor
diff --git a/dns_updater.hpp b/dns_updater.hpp
new file mode 100644
index 0000000..44c0e32
--- /dev/null
+++ b/dns_updater.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <experimental/filesystem>
+
+namespace phosphor
+{
+namespace network
+{
+namespace dns
+{
+namespace updater
+{
+
+namespace fs = std::experimental::filesystem;
+
+constexpr auto RESOLV_CONF = "/etc/resolv.conf";
+
+/** @brief Reads DNS entries supplied by DHCP and updates specified file
+ *
+ *  @param[in] inFile  - File having DNS entries supplied by DHCP
+ *  @param[in] outFile - File to write the nameserver entries to
+ */
+void processDNSEntries(const fs::path& inFile,
+                       const fs::path& outFile);
+
+/** @brief User callback handler invoked by inotify watcher
+ *
+ *  Needed to enable production and test code so that the right
+ *  callback functions could be implemented
+ *
+ *  @param[in] inFile - File having DNS entries supplied by DHCP
+ */
+inline void processDNSEntries(const fs::path& inFile)
+{
+    return processDNSEntries(inFile, RESOLV_CONF);
+}
+
+} // namepsace updater
+} // namepsace dns
+} // namespace network
+} // namespace phosphor
diff --git a/test/Makefile.am b/test/Makefile.am
index 024fa25..5c70fbe 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,7 +2,7 @@
 
 TESTS = $(check_PROGRAMS)
 
-check_PROGRAMS = test
+check_PROGRAMS = test test_dns_updater
 
 test_SOURCES = \
 	test_util.cpp \
@@ -12,20 +12,30 @@
 	test_config_parser.cpp \
 	test_vlan_interface.cpp
 
-test_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS)
+test_dns_updater_SOURCES = test_dns_updater.cpp
 
-test_CXXFLAGS = $(PTHREAD_CFLAGS) \
-				$(SYSTEMD_CFLAGS) \
-				$(SDBUSPLUS_CFLAGS) \
-				$(PHOSPHOR_LOGGING_CFLAGS) \
-				$(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+generic_cpp_flags = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS)
 
-test_LDFLAGS =	-lgtest_main -lgtest -lstdc++fs \
-				$(OESDK_TESTCASE_FLAGS) \
-				$(SYSTEMD_LIBS) \
-				$(SDBUSPLUS_LIBS) \
-				$(PHOSPHOR_LOGGING_LIBS) \
-				$(PHOSPHOR_DBUS_INTERFACES_LIBS)
+generic_cxx_flags = $(PTHREAD_CFLAGS) \
+					$(SYSTEMD_CFLAGS) \
+					$(SDBUSPLUS_CFLAGS) \
+					$(PHOSPHOR_LOGGING_CFLAGS) \
+					$(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+
+generic_ld_flags =  -lgtest_main -lgtest -lstdc++fs \
+					$(OESDK_TESTCASE_FLAGS) \
+					$(SYSTEMD_LIBS) \
+					$(SDBUSPLUS_LIBS) \
+					$(PHOSPHOR_LOGGING_LIBS) \
+					$(PHOSPHOR_DBUS_INTERFACES_LIBS)
+
+test_CPPFLAGS = ${generic_cpp_flags}
+test_CXXFLAGS = ${generic_cxx_flags}
+test_LDFLAGS  = ${generic_ld_flags}
+
+test_dns_updater_CPPFLAGS = ${generic_cpp_flags}
+test_dns_updater_CXXFLAGS = ${generic_cxx_flags}
+test_dns_updater_LDFLAGS  = ${generic_ld_flags}
 
 test_LDADD = $(top_builddir)/ethernet_interface.o \
 			$(top_builddir)/network_manager.o \
@@ -40,3 +50,5 @@
 			$(top_builddir)/vlan_interface.o \
 			$(top_builddir)/xyz/openbmc_project/Network/VLAN/Create/phosphor_network_manager-server.o \
 			$(top_builddir)/xyz/openbmc_project/Network/IP/Create/phosphor_network_manager-server.o
+
+test_dns_updater_LDADD = $(top_builddir)/dns_updater.o
diff --git a/test/test_dns_updater.cpp b/test/test_dns_updater.cpp
new file mode 100644
index 0000000..8fb4bcb
--- /dev/null
+++ b/test/test_dns_updater.cpp
@@ -0,0 +1,78 @@
+#include "dns_updater.hpp"
+
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <experimental/filesystem>
+
+static constexpr auto IN_FILE = "/tmp/netif_state";
+static constexpr auto OUT_FILE = "/tmp/resolv.conf";
+static constexpr auto COMPARE_FILE = "/tmp/resolv_compare.conf";
+static constexpr auto DNS_ENTRY_1 = "DNS=1.2.3.4\n";
+static constexpr auto DNS_ENTRY_2 = "DNS=5.6.7.8\n";
+
+namespace fs = std::experimental::filesystem;
+
+class DnsUpdateTest : public ::testing::Test
+{
+    public:
+        // Gets called as part of each TEST_F construction
+        DnsUpdateTest()
+        {
+            // Create a file containing DNS entries like in netif/state
+            std::ofstream file(IN_FILE);
+            file << DNS_ENTRY_1;
+            file << DNS_ENTRY_2;
+
+            // Create a file to compare the results against
+            std::ofstream compare(COMPARE_FILE);
+            compare << "### Generated by phosphor-networkd ###\n";
+            compare << "nameserver 1.2.3.4\n";
+            compare << "nameserver 5.6.7.8\n";
+        }
+
+        // Gets called as part of each TEST_F destruction
+        ~DnsUpdateTest()
+        {
+            if (fs::exists(IN_FILE))
+            {
+                fs::remove(IN_FILE);
+            }
+            if (fs::exists(OUT_FILE))
+            {
+                fs::remove(OUT_FILE);
+            }
+            if (fs::exists(COMPARE_FILE))
+            {
+                fs::remove(COMPARE_FILE);
+            }
+        }
+};
+
+/** @brief Makes outfile is updated with right contents
+ */
+TEST_F(DnsUpdateTest, validateOutFile)
+{
+    phosphor::network::dns::updater::processDNSEntries(IN_FILE, OUT_FILE);
+
+    // Read files and compare
+    std::ifstream resolv(OUT_FILE);
+    std::ifstream compare(COMPARE_FILE);
+
+    // From actual file
+    std::string resolvEntry{};
+    std::string resolvContent{};
+    while (std::getline(resolv, resolvEntry))
+    {
+        resolvContent += resolvEntry;
+    }
+
+    // From compare file
+    std::string compareEntry{};
+    std::string compareContent{};
+    while (std::getline(compare, compareEntry))
+    {
+        compareContent += compareEntry;
+    }
+    EXPECT_EQ(resolvContent, compareContent);
+}