Implement Multi System LastResetTime

```
curl localhost/redfish/v1/Systems/system1 | jq .LastResetTime
"2025-06-06T05:51:41+00:00"
curl localhost/redfish/v1/Systems/system2 | jq .LastResetTime
"2025-06-06T05:51:20+00:00"
```
after reset host1 and host2, reset time is updated
```
curl localhost/redfish/v1/Systems/system1 | jq .LastResetTime
"2025-06-06T22:36:20+00:00"
curl localhost/redfish/v1/Systems/system2 | jq .LastResetTime
"2025-06-06T22:37:22+00:00"
```

Tested: tested on multhost system
Google-Bug-Id: 415354941
Change-Id: I7eefbdb2851bf693145f0625ad07c107e5bfe6a8
Signed-off-by: Hao Zhou <haoooamazing@google.com>
diff --git a/meson.build b/meson.build
index 60cd322..55a5fba 100644
--- a/meson.build
+++ b/meson.build
@@ -592,6 +592,7 @@
     'test/redfish-core/lib/log_services_test.cpp',
     'test/redfish-core/lib/service_root_test.cpp',
     'test/redfish-core/lib/system_test.cpp',
+    'test/redfish-core/lib/system_multi_host_test.cpp',
     'test/redfish-core/lib/thermal_subsystem_test.cpp',
     'test/redfish-core/lib/power_test.cpp',
     'test/redfish-core/lib/power_supply_test.cpp',
diff --git a/meson_options.txt b/meson_options.txt
index 4c56ba8..d0a9c39 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -808,7 +808,7 @@
 option(
     'snapshot-filepath-platform23',
     type : 'string',
-    value : '/tmpfs/src/ci_workspace/openbmc-build-scripts/additional/scrubbed_gBMCwebManagedStore_platform23_0_2025_05_09.json',
+    value : '/tmpfs/src/ci_workspace/openbmc-build-scripts/additional/scrubbed_gBMCwebManagedStore_platform23_0_2025_06_11.json',
     description : 'File location to the snapshot used for unit tests.'
 )
 
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 6f0d96d..7a0add1 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -63,6 +63,9 @@
 constexpr std::array<std::string_view, 1> hostStateInterfaces{
     {"xyz.openbmc_project.State.Host"}};
 
+constexpr std::array<std::string_view, 1> chassisStateInterfaces{
+    {"xyz.openbmc_project.State.Chassis"}};
+
 /**
  * @brief Updates the Functional State of DIMMs
  *
@@ -3850,31 +3853,67 @@
         sdbusplus::message::object_path(systemObjectPath + "/host_power"),
         sdbusplus::message::object_path("/xyz/openbmc_project/state"), 0,
         hostStateInterfaces, requestContext,
-        [asyncResp, systemObjectPath](
-            const boost::system::error_code& ec,
-            const dbus::utility::MapperGetSubTreeResponse& objects) {
+        [asyncResp, systemObjectPath,
+         multiHost](const boost::system::error_code& ec,
+                    const dbus::utility::MapperGetSubTreeResponse& objects) {
         if (ec)
         {
             BMCWEB_LOG_ERROR
-                << "Chassis power control not associated with system object";
+                << "Host power control not associated with system object";
             messages::internalError(asyncResp->res);
             return;
         }
 
-        // There should only be one chassis power control object associated with
+        // There should only be one host power control object associated with
         // this system
         if (objects.size() > 1)
         {
             BMCWEB_LOG_ERROR
-                << "Too many chassis power control objects associated with the system";
+                << "Too many host power control objects associated with the system";
             messages::internalError(asyncResp->res);
             return;
         }
 
         getHostState(asyncResp, systemObjectPath, objects);
-        getLastResetTime(asyncResp, systemObjectPath, objects);
+        if (!multiHost)
+        {
+            getLastResetTime(asyncResp, systemObjectPath, objects);
+        }
     });
 
+    // Handling last reset time for multi-system
+    if (multiHost)
+    {
+        managedStore::GetManagedObjectStore()->getAssociatedSubTree(
+            sdbusplus::message::object_path(systemObjectPath +
+                                            "/chassis_power"),
+            sdbusplus::message::object_path("/xyz/openbmc_project/state"), 0,
+            chassisStateInterfaces, requestContext,
+            [asyncResp, systemObjectPath](
+                const boost::system::error_code& ec,
+                const dbus::utility::MapperGetSubTreeResponse& objects) {
+            if (ec)
+            {
+                BMCWEB_LOG_ERROR
+                    << "Chassis power control not associated with system object";
+                messages::internalError(asyncResp->res);
+                return;
+            }
+
+            // There should only be one chassis power control object associated
+            // with this system
+            if (objects.size() > 1)
+            {
+                BMCWEB_LOG_ERROR
+                    << "Too many chassis power control objects associated with the system";
+                messages::internalError(asyncResp->res);
+                return;
+            }
+
+            getLastResetTime(asyncResp, systemObjectPath, objects);
+        });
+    }
+
     getPCIeDeviceList(asyncResp, systemName, "PCIeDevices");
 
     // Handling multi-system and single-system separately. In the future, the
diff --git a/test/redfish-core/lib/bios_test.cpp b/test/redfish-core/lib/bios_test.cpp
index 06dd428..306f5e0 100644
--- a/test/redfish-core/lib/bios_test.cpp
+++ b/test/redfish-core/lib/bios_test.cpp
@@ -98,7 +98,7 @@
             key);
     ASSERT_TRUE(systemObjectsPathsStatusOr.ok());
 
-    // TODO(b/416746677): Uncomment until the bug fixed
+    // TODO(b/416746677): Uncomment after the bug is fixed
     // ASSERT_EQ(systemObjectsPathsStatusOr.value()->managedType,
     //           ManagedType::kManagedSubtreePaths);
 
@@ -307,7 +307,7 @@
             key);
     ASSERT_TRUE(systemObjectsPathsStatusOr.ok());
 
-    // TODO(b/416746677): Uncomment until the bug fixed
+    // TODO(b/416746677): Uncomment after the bug is fixed
     // ASSERT_EQ(systemObjectsPathsStatusOr.value()->managedType,
     //           ManagedType::kManagedSubtreePaths);
 
diff --git a/test/redfish-core/lib/system_multi_host_test.cpp b/test/redfish-core/lib/system_multi_host_test.cpp
new file mode 100644
index 0000000..aad7d11
--- /dev/null
+++ b/test/redfish-core/lib/system_multi_host_test.cpp
@@ -0,0 +1,150 @@
+#include "absl/cleanup/cleanup.h"
+#include "bmcweb_config.h"
+
+#include "app.hpp"
+#include "async_resp.hpp"
+#include "http_response.hpp"
+#include "nlohmann/json.hpp"
+#include "snapshot_fixture.hpp"
+#include "systems.hpp"
+
+#include <memory>
+#include <vector>
+
+#include <gmock/gmock.h> // IWYU pragma: keep
+#include <gtest/gtest.h> // IWYU pragma: keep
+
+// IWYU pragma: no_include <gtest/gtest-message.h>
+// IWYU pragma: no_include <gtest/gtest-test-part.h>
+// IWYU pragma: no_include "gtest/gtest_pred_impl.h"
+// IWYU pragma: no_include <gmock/gmock-matchers.h>
+// IWYU pragma: no_include <gtest/gtest-matchers.h>
+
+namespace redfish
+{
+namespace
+{
+
+using ::dbus::utility::DbusVariantType;
+using ::managedStore::KeyType;
+using ::managedStore::ManagedObjectStoreContext;
+using ::managedStore::ManagedType;
+using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeAction;
+using ::managedStore::SimulateSuccessfulAsyncPostDbusCallThreadSafeAction;
+using ::managedStore::ValueType;
+using ::testing::_;
+using ::testing::An;
+
+std::shared_ptr<ValueType> CreateBadMockAssociatedSubtreeForMultiSystem()
+{
+    dbus::utility::MapperGetSubTreeResponse mockAssociatedSubtree = {
+        std::make_pair(
+            "/xyz/openbmc_project/state/chassis1",
+            dbus::utility::MapperServiceMap{
+                {std::make_pair("xyz.openbmc_project.Chassis.Buttons1",
+                                std::vector<std::string>{
+                                    "org.freedesktop.DBus.Introspectable",
+                                    "org.freedesktop.DBus.Peer",
+                                    "org.freedesktop.DBus.Properties",
+                                    "xyz.openbmc_project.State.Chassis",
+                                }),
+                 std::make_pair(
+                     "xyz.openbmc_project.Control.Host.RestartCause1",
+                     std::vector<std::string>{
+                         "org.freedesktop.DBus.Introspectable",
+                         "org.freedesktop.DBus.Peer",
+                         "org.freedesktop.DBus.Properties",
+                         "xyz.openbmc_project.State.Chassis",
+                     })}}),
+        std::make_pair(
+            "/xyz/openbmc_project/state/chassis2",
+            dbus::utility::MapperServiceMap{
+                {std::make_pair("xyz.openbmc_project.Chassis.Buttons1",
+                                std::vector<std::string>{
+                                    "org.freedesktop.DBus.Introspectable",
+                                    "org.freedesktop.DBus.Peer",
+                                    "org.freedesktop.DBus.Properties",
+                                    "xyz.openbmc_project.State.Chassis",
+                                }),
+                 std::make_pair(
+                     "xyz.openbmc_project.Control.Host.RestartCause1",
+                     std::vector<std::string>{
+                         "org.freedesktop.DBus.Introspectable",
+                         "org.freedesktop.DBus.Peer",
+                         "org.freedesktop.DBus.Properties",
+                         "xyz.openbmc_project.State.Chassis",
+                     })}}),
+    };
+    return managedStore::MockManagedStoreTest::CreateValueType(
+        std::move(mockAssociatedSubtree));
+}
+
+TEST_F(SnapshotFixture_Platform23,
+       GetSystemHostPowerAssociatedSubTreeHasMoreThanOneObjectsForMultiSystem)
+{
+    // Looking for
+    // kManagedAssociatedSubtree|/xyz/openbmc_project/state|0|xyz.openbmc_project.State.Chassis|/xyz/openbmc_project/inventory/system/board/platform23/system1/chassis_power
+    KeyType key(
+        ManagedType::kManagedAssociatedSubtree,
+        "/xyz/openbmc_project/inventory/system/board/platform23/system1/chassis_power",
+        "/xyz/openbmc_project/state", 0, {"xyz.openbmc_project.State.Chassis"});
+
+    absl::StatusOr<std::shared_ptr<ValueType>>
+        chassisPowerAssociatedSubtreeStatusOr =
+            managedStore::GetManagedObjectStore()
+                ->getMockObjectFromManagedStore(key);
+    ASSERT_TRUE(chassisPowerAssociatedSubtreeStatusOr.ok());
+
+    // TODO(b/416746677): Uncomment after the bug is fixed
+    // ASSERT_EQ(systemObjectsPathsStatusOr.value()->managedType,
+    //           ManagedType::kManagedSubtreePaths);
+
+    std::optional<dbus::utility::MapperGetSubTreeResponse>
+        originalAssociatedSubtree =
+            chassisPowerAssociatedSubtreeStatusOr.value()->managedSubtree;
+
+    ASSERT_TRUE(originalAssociatedSubtree.has_value());
+
+    ASSERT_TRUE(managedStore::GetManagedObjectStore()
+                    ->upsertMockObjectIntoManagedStore(
+                        key, CreateBadMockAssociatedSubtreeForMultiSystem())
+                    .ok());
+
+    absl::Cleanup mockManagedStoreResetter = [key,
+                                              originalAssociatedSubtree]() {
+        ASSERT_TRUE(
+            managedStore::GetManagedObjectStore()
+                ->upsertMockObjectIntoManagedStore(
+                    key, managedStore::MockManagedStoreTest::CreateValueType(
+                             originalAssociatedSubtree.value()))
+                .ok());
+    };
+
+    handleComputerSystem(
+        share_async_resp_,
+        "/xyz/openbmc_project/inventory/system/board/platform23/system1",
+        "system1", true);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(),
+              boost::beast::http::status::internal_server_error);
+}
+
+TEST_F(SnapshotFixture_Platform23, GetSystemHostPowerAssociatedSubTreeSuccess)
+{
+    std::cerr << "Hao: start \n";
+
+    handleComputerSystem(
+        share_async_resp_,
+        "/xyz/openbmc_project/inventory/system/board/platform23/system1",
+        "system1", true);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
+    std::cerr << "Hao: Done \n";
+}
+
+} // namespace
+} // namespace redfish
diff --git a/test/redfish-core/lib/system_test.cpp b/test/redfish-core/lib/system_test.cpp
index 6f8bb6d..ed209f3 100644
--- a/test/redfish-core/lib/system_test.cpp
+++ b/test/redfish-core/lib/system_test.cpp
@@ -1,3 +1,4 @@
+#include "absl/cleanup/cleanup.h"
 #include "app.hpp"
 #include "bmcweb_config.h"
 
@@ -315,6 +316,152 @@
     }
 }
 
+TEST_F(SnapshotFixture, GetSystemHostPowerAssociatedSubTreeFailed)
+{
+    // Looking for
+    // kManagedAssociatedSubtree|/xyz/openbmc_project/state|0|xyz.openbmc_project.State.Host|/host_power
+    KeyType key(ManagedType::kManagedAssociatedSubtree, "/host_power",
+                "/xyz/openbmc_project/state", 0,
+                {"xyz.openbmc_project.State.Host"});
+
+    absl::StatusOr<std::shared_ptr<ValueType>>
+        associatedSubtreeObjectsStatusOr =
+            managedStore::GetManagedObjectStore()
+                ->getMockObjectFromManagedStore(key);
+    ASSERT_TRUE(associatedSubtreeObjectsStatusOr.ok());
+
+    // TODO(b/416746677): Uncomment after the bug is fixed
+    // ASSERT_EQ(associatedSubtreeObjectsStatusOr.value()->managedType,
+    //           ManagedType::kManagedSubtreePaths);
+
+    std::optional<dbus::utility::MapperGetSubTreeResponse>
+        originalAssociatedSubtree =
+            associatedSubtreeObjectsStatusOr.value()->managedSubtree;
+
+    ASSERT_TRUE(originalAssociatedSubtree.has_value());
+
+    ASSERT_TRUE(
+        managedStore::GetManagedObjectStore()
+            ->upsertMockObjectIntoManagedStore(
+                key, managedStore::MockManagedStoreTest::CreateErrorValueType(
+                         originalAssociatedSubtree.value(),
+                         boost::system::errc::make_error_code(
+                             boost::system::errc::io_error)))
+            .ok());
+
+    absl::Cleanup mockManagedStoreResetter = [key,
+                                              originalAssociatedSubtree]() {
+        ASSERT_TRUE(
+            managedStore::GetManagedObjectStore()
+                ->upsertMockObjectIntoManagedStore(
+                    key, managedStore::MockManagedStoreTest::CreateValueType(
+                             originalAssociatedSubtree.value()))
+                .ok());
+    };
+
+    handleComputerSystem(share_async_resp_, "", "system", false);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(),
+              boost::beast::http::status::internal_server_error);
+}
+
+std::shared_ptr<ValueType> CreateMockAssociatedSubtree()
+{
+    dbus::utility::MapperGetSubTreeResponse mockAssociatedSubtree = {
+        std::make_pair(
+            "/xyz/openbmc_project/state/host1",
+            dbus::utility::MapperServiceMap{
+                {std::make_pair(
+                    "xyz.openbmc_project.Chassis.Buttons1",
+                    std::vector<std::string>{
+                        "org.freedesktop.DBus.Introspectable",
+                        "org.freedesktop.DBus.Peer",
+                        "org.freedesktop.DBus.Properties",
+                        "xyz.openbmc_project.State.Host",
+                                }),
+                 std::make_pair(
+                     "xyz.openbmc_project.Control.Host.RestartCause1",
+                     std::vector<std::string>{
+                         "org.freedesktop.DBus.Introspectable",
+                         "org.freedesktop.DBus.Peer",
+                         "org.freedesktop.DBus.Properties",
+                         "xyz.openbmc_project.State.Host",
+                     })}}),
+        std::make_pair(
+            "/xyz/openbmc_project/state/host2",
+            dbus::utility::MapperServiceMap{
+                {std::make_pair(
+                    "xyz.openbmc_project.Chassis.Buttons1",
+                    std::vector<std::string>{
+                        "org.freedesktop.DBus.Introspectable",
+                        "org.freedesktop.DBus.Peer",
+                        "org.freedesktop.DBus.Properties",
+                        "xyz.openbmc_project.State.Host",
+                    }),
+                 std::make_pair(
+                     "xyz.openbmc_project.Control.Host.RestartCause1",
+                     std::vector<std::string>{
+                         "org.freedesktop.DBus.Introspectable",
+                         "org.freedesktop.DBus.Peer",
+                         "org.freedesktop.DBus.Properties",
+                         "xyz.openbmc_project.State.Host",
+                     })}}),
+    };
+    return managedStore::MockManagedStoreTest::CreateValueType(
+        std::move(mockAssociatedSubtree));
+}
+
+TEST_F(SnapshotFixture,
+       GetSystemHostPowerAssociatedSubTreeHasMoreThanOneObjects)
+{
+    crow::Logger::setLogLevel(crow::LogLevel::Error);
+    // Looking for
+    // kManagedAssociatedSubtree|/xyz/openbmc_project/state|0|xyz.openbmc_project.State.Host|/host_power
+    KeyType key(ManagedType::kManagedAssociatedSubtree, "/host_power",
+                "/xyz/openbmc_project/state", 0,
+                {"xyz.openbmc_project.State.Host"});
+
+    absl::StatusOr<std::shared_ptr<ValueType>>
+        associatedSubtreeObjectsStatusOr =
+            managedStore::GetManagedObjectStore()
+                ->getMockObjectFromManagedStore(key);
+    ASSERT_TRUE(associatedSubtreeObjectsStatusOr.ok());
+
+    // TODO(b/416746677): Uncomment after the bug is fixed
+    // ASSERT_EQ(associatedSubtreeObjectsStatusOr.value()->managedType,
+    //           ManagedType::kManagedSubtreePaths);
+
+    std::optional<dbus::utility::MapperGetSubTreeResponse>
+        originalAssociatedSubtree =
+            associatedSubtreeObjectsStatusOr.value()->managedSubtree;
+
+    ASSERT_TRUE(originalAssociatedSubtree.has_value());
+
+    ASSERT_TRUE(managedStore::GetManagedObjectStore()
+                    ->upsertMockObjectIntoManagedStore(
+                        key, CreateMockAssociatedSubtree())
+                    .ok());
+
+    absl::Cleanup mockManagedStoreResetter = [key,
+                                              originalAssociatedSubtree]() {
+        ASSERT_TRUE(
+            managedStore::GetManagedObjectStore()
+                ->upsertMockObjectIntoManagedStore(
+                    key, managedStore::MockManagedStoreTest::CreateValueType(
+                             originalAssociatedSubtree.value()))
+                .ok());
+    };
+
+    handleComputerSystem(share_async_resp_, "", "system", false);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(),
+              boost::beast::http::status::internal_server_error);
+}
+
 TEST_F(SnapshotFixture, PostSystemResetSingleSystemChassisResetOnSuccessDelay){
     handlePostComputerSystemReset(app_, CreateRequest("{\"ResetType\":\"ForceOff\", \"Delay\":1} "), share_async_resp_, "system");