rsyslog-config: Support IPv6 address

The IPv6 address requires `[]` in the config file. Add support for this
format so that user could set IPv6 address on DBus, and this service
will add `[]` in the config file to make it work correctly.

Split the logic in restore() into a separate function parseConfig() so
that it is easier to test.

Tested: Verify both IPv4 and IPv6 address could be set to rsyslog-config
        and verify it works correctly.
        Added several IPv6 related test cases.

Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: I2135e3b0e916947449ab5d0cfa9669a98349226e
diff --git a/test/remote_logging_test_config.cpp b/test/remote_logging_test_config.cpp
index cba54ea..53298c6 100644
--- a/test/remote_logging_test_config.cpp
+++ b/test/remote_logging_test_config.cpp
@@ -5,6 +5,13 @@
 
 namespace phosphor
 {
+
+namespace rsyslog_config::internal
+{
+extern std::optional<std::pair<std::string, uint32_t>>
+    parseConfig(std::istream& ss);
+}
+
 namespace logging
 {
 namespace test
@@ -55,6 +62,78 @@
     EXPECT_EQ(getConfig(configFilePath.c_str()), "*.* ~");
 }
 
+TEST_F(TestRemoteLogging, testGoodIPv6Config)
+{
+    config->address("abcd:ef01::01");
+    config->port(50000);
+    EXPECT_EQ(getConfig(configFilePath.c_str()), "*.* @@[abcd:ef01::01]:50000");
+}
+
+TEST_F(TestRemoteLogging, parseConfigGoodIpv6)
+{
+    // A good case
+    std::string str = "*.* @@[abcd:ef01::01]:50000";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(ret->first, "abcd:ef01::01");
+    EXPECT_EQ(ret->second, 50000);
+}
+
+TEST_F(TestRemoteLogging, parseConfigBadIpv6WithoutRightBracket)
+{
+    // Bad case: without ]
+    std::string str = "*.* @@[abcd:ef01::01:50000";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_FALSE(ret);
+}
+
+TEST_F(TestRemoteLogging, parseConfigBadIpv6WithoutLeftBracket)
+{
+    // Bad case: without [
+    std::string str = "*.* @@abcd:ef01::01]:50000";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_FALSE(ret);
+}
+
+TEST_F(TestRemoteLogging, parseConfigBadIpv6WithoutPort)
+{
+    // Bad case: without port
+    std::string str = "*.* @@[abcd:ef01::01]:";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_FALSE(ret);
+}
+
+TEST_F(TestRemoteLogging, parseConfigBadIpv6InvalidPort)
+{
+    // Bad case: without port
+    std::string str = "*.* @@[abcd:ef01::01]:xxx";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_FALSE(ret);
+}
+
+TEST_F(TestRemoteLogging, parseConfigBadIpv6WihtoutColon)
+{
+    // Bad case: invalid IPv6 address
+    std::string str = "*.* @@[abcd:ef01::01]";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_FALSE(ret);
+}
+
+TEST_F(TestRemoteLogging, parseConfigBadEmpty)
+{
+    // Bad case: invalid IPv6 address
+    std::string str = "";
+    std::stringstream ss(str);
+    auto ret = phosphor::rsyslog_config::internal::parseConfig(ss);
+    EXPECT_FALSE(ret);
+}
+
 } // namespace test
 } // namespace logging
 } // namespace phosphor