Add support for individual property update

SNMP Manager D-Bus object doesn't have support
for individual D-Bus property update.
This commit adds the support for the same.

Resolves openbmc/phosphor-snmp#2

Change-Id: Ic72366b6b18190e66e23d400a5f2c95037947809
Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
diff --git a/snmp_client.cpp b/snmp_client.cpp
index 2d2e1d5..52eb744 100644
--- a/snmp_client.cpp
+++ b/snmp_client.cpp
@@ -1,5 +1,6 @@
 #include "snmp_client.hpp"
 #include "snmp_conf_manager.hpp"
+#include "snmp_serialize.hpp"
 
 namespace phosphor
 {
@@ -21,6 +22,34 @@
     emit_object_added();
 }
 
+std::string Client::address(std::string value)
+{
+    if (value == Ifaces::address())
+    {
+        return value;
+    }
+
+    parent.checkClientConfigured(value, port());
+
+    auto addr = Ifaces::address(value);
+    serialize(id, *this, parent.dbusPersistentLocation);
+    return addr;
+}
+
+uint16_t Client::port(uint16_t value)
+{
+    if (value == Ifaces::port())
+    {
+        return value;
+    }
+
+    parent.checkClientConfigured(address(), value);
+
+    auto port = Ifaces::port(value);
+    serialize(id, *this, parent.dbusPersistentLocation);
+    return port;
+}
+
 void Client::delete_()
 {
     parent.deleteSNMPClient(id);
diff --git a/snmp_client.hpp b/snmp_client.hpp
index aab72cc..51ebabb 100644
--- a/snmp_client.hpp
+++ b/snmp_client.hpp
@@ -61,6 +61,26 @@
     {
     }
 
+    /** @brief Update the address of the object.
+     *
+     *  @param[in] value - IP address
+     *
+     *  @return On success the updated IP address
+     */
+    std::string address(std::string value) override;
+
+    /** @brief Update the port
+     *
+     *  @param[in] value - port number
+     *
+     *  @return On success the updated port number
+     */
+    uint16_t port(uint16_t value) override;
+
+    using sdbusplus::xyz::openbmc_project::Network::server::Client::address;
+
+    using sdbusplus::xyz::openbmc_project::Network::server::Client::port;
+
     /** @brief Delete this d-bus object.
      */
     void delete_() override;
diff --git a/test/Makefile.am.include b/test/Makefile.am.include
index 97b018c..9bbf050 100644
--- a/test/Makefile.am.include
+++ b/test/Makefile.am.include
@@ -31,7 +31,8 @@
 	%reldir%/test_error_notification.cpp \
 	%reldir%/test_snmp_conf_manager.cpp \
 	%reldir%/test_snmp_util.cpp \
-	%reldir%/test_snmp_serialize.cpp
+	%reldir%/test_snmp_serialize.cpp \
+	%reldir%/test_snmp_client.cpp
 
 test_notification_LDADD = $(top_builddir)/phosphor_network_snmpconf-snmp_conf_manager.o \
 	$(top_builddir)/phosphor_network_snmpconf-snmp_client.o \
diff --git a/test/test_snmp_client.cpp b/test/test_snmp_client.cpp
new file mode 100644
index 0000000..fe49f2b
--- /dev/null
+++ b/test/test_snmp_client.cpp
@@ -0,0 +1,83 @@
+#include <gtest/gtest.h>
+
+#include <xyz/openbmc_project/Common/error.hpp>
+
+#include "snmp_conf_manager.hpp"
+#include "snmp_serialize.hpp"
+
+namespace phosphor
+{
+namespace network
+{
+namespace snmp
+{
+
+using InvalidArgument =
+    sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
+
+auto mgrObjPath = "/xyz/openbmc_test/snmp/manager";
+
+class TestSNMPClient : public testing::Test
+{
+  public:
+    sdbusplus::bus::bus bus;
+    ConfManager manager;
+    std::string confDir;
+    TestSNMPClient() :
+        bus(sdbusplus::bus::new_default()), manager(bus, mgrObjPath)
+    {
+        char tmp[] = "/tmp/snmpClient.XXXXXX";
+        std::string confDir = mkdtemp(tmp);
+        manager.dbusPersistentLocation = confDir;
+    }
+
+    ~TestSNMPClient()
+    {
+        fs::remove_all(manager.dbusPersistentLocation);
+    }
+};
+
+TEST_F(TestSNMPClient, UpdateProperty)
+{
+    std::string objPath = mgrObjPath;
+    objPath += "/" + std::to_string(1);
+    Client client(bus, objPath.c_str(), manager, "1.1.1.1", 202);
+    EXPECT_EQ(client.address(), "1.1.1.1");
+    EXPECT_EQ(client.port(), 202);
+    client.address("2.2.2.2");
+    EXPECT_EQ(client.address(), "2.2.2.2");
+    client.port(404);
+    EXPECT_EQ(client.port(), 404);
+}
+
+TEST_F(TestSNMPClient, AddEmptyAddress)
+{
+    std::string objPath = mgrObjPath;
+    objPath += "/" + std::to_string(1);
+    Client client(bus, objPath.c_str(), manager, "1.1.1.1", 202);
+    EXPECT_EQ(client.address(), "1.1.1.1");
+    EXPECT_EQ(client.port(), 202);
+
+    EXPECT_THROW(client.address(""), InvalidArgument);
+}
+
+TEST_F(TestSNMPClient, CheckPersistency)
+{
+    std::string objPath = mgrObjPath;
+    objPath += "/" + std::to_string(1);
+
+    Client client(bus, objPath.c_str(), manager, "1.1.1.1", 23);
+    client.address("2.2.2.2");
+
+    Client restoreClient(bus, objPath.c_str(), manager);
+    auto persistentPath = manager.dbusPersistentLocation;
+    persistentPath += "/1";
+    deserialize(persistentPath, restoreClient);
+
+    EXPECT_EQ("2.2.2.2", restoreClient.address());
+    EXPECT_EQ(23, restoreClient.port());
+}
+
+} // namespace snmp
+} // namespace network
+} // namespace phosphor