implement new reset type TrayPowerCycle for /redfish/v1/Managers/bmc/ResetActionInfo

Tested:
- From handler side, added unit test in manager_test.cpp
- From bmc side, flashed image on bmc and tested with curl and uptime

Detailed log can be found here: https://paste.googleplex.com/4649222043074560

Related Design doc: go/redefine-redfish-tray-powercycle
Google-Bug-Id: 396463354
Change-Id: I4bf75ce0fb73a7ecf837eba5e24351b3b9ed0f5d
Signed-off-by: Yichao Wang <wangyic@google.com>
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index c3192e1..38e9165 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -36,6 +36,7 @@
 #include <sdbusplus/asio/property.hpp>
 #include <sdbusplus/unpack_properties.hpp>
 #include <utils/location_utils.hpp>
+#include "chassis.hpp"
 
 #include <algorithm>
 #include <array>
@@ -143,6 +144,16 @@
         doBMCForceRestart(asyncResp);
         return;
     }
+    if (resetType == "TrayPowerCycle")
+    {
+        BMCWEB_LOG_DEBUG << "Proceeding with " << resetType;
+        // We don't support delay powercycle for now. If S4 wants to use it in
+        // the future, we will add it.
+        std::optional<int> delayTimeSecs = std::nullopt;
+        doChassisPowerCycle(asyncResp, delayTimeSecs);
+        return;
+    }
+
     BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " << resetType;
     messages::actionParameterNotSupported(asyncResp->res, resetType,
                                           "ResetType");
@@ -261,6 +272,7 @@
     nlohmann::json::array_t allowableValues;
     allowableValues.emplace_back("GracefulRestart");
     allowableValues.emplace_back("ForceRestart");
+    allowableValues.emplace_back("TrayPowerCycle");
     parameter["AllowableValues"] = std::move(allowableValues);
 
     nlohmann::json::array_t parameters;
diff --git a/test/redfish-core/lib/manager_test.cpp b/test/redfish-core/lib/manager_test.cpp
index 162dbe7..ab1c4e1 100644
--- a/test/redfish-core/lib/manager_test.cpp
+++ b/test/redfish-core/lib/manager_test.cpp
@@ -160,5 +160,51 @@
         "n/a");
 }
 
+TEST_F(SnapshotFixture, PostManagerResetActionGood){
+// using expected call to mitigate the memory issue in valgrind
+// https://b.corp.google.com/issues/416295689
+// https://b.corp.google.com/issues/416608762
+    EXPECT_CALL(*managedStore::GetManagedObjectStore(),
+                PostDbusCallToIoContextThreadSafe(
+                    testing::_,
+                    testing::An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
+                    "xyz.openbmc_project.State.Chassis",
+                    testing::An<const std::string&>(),
+                    "org.freedesktop.DBus.Properties",
+                    "Set",
+                    "xyz.openbmc_project.State.Chassis",
+                    "RequestedPowerTransition",
+                    dbus::utility::DbusVariantType("xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
+                ))
+        .WillOnce(
+            managedStore::SimulateSuccessfulAsyncPostDbusCallThreadSafeAction::
+            SimulateSuccessfulAsyncPostDbusCall());
+
+    handlePostManagerResetAction(app_, CreateRequest("{\"ResetType\":\"TrayPowerCycle\"} "), share_async_resp_);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(),boost::beast::http::status::ok);
+}
+
+TEST_F(SnapshotFixture, PostManagerResetActionBadResetType){
+    handlePostManagerResetAction(app_, CreateRequest("{\"ResetType\":\"Typo\"} "), share_async_resp_);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(),boost::beast::http::status::bad_request);
+}
+
+TEST_F(SnapshotFixture, handleManagerResetActionInfoAllowableValues){
+    handleManagerResetActionInfo(app_, CreateRequest(""), share_async_resp_);
+
+    RunIoUntilDone();
+
+    EXPECT_EQ(share_async_resp_->res.result(),boost::beast::http::status::ok);
+
+    auto allowable_values = share_async_resp_->res.jsonValue["Parameters"][0]["AllowableValues"];
+    EXPECT_THAT(allowable_values, testing::ElementsAre("GracefulRestart", "ForceRestart", "TrayPowerCycle"));
+}
+
 } // namespace
 } // namespace redfish