gbmcweb: Expose Corrupted property in RawEeproms endpoint

Google-Bug-Id:492137013,570840373
PiperOrigin-RevId: 1003372131
Change-Id: Idc33a9334908178670af4530a4c24b4d191b5bb0
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index e182dcc..d35fee4 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -2689,6 +2689,7 @@
               uint32_t address = 0;
               bool hasBus = false;
               bool hasAddress = false;
+              std::optional<bool> corrupted;
 
               for (const auto& [propertyName, value] : propertiesList) {
                 if (propertyName == "Bus") {
@@ -2711,6 +2712,11 @@
                     address = static_cast<uint32_t>(*a64);
                     hasAddress = true;
                   }
+                } else if (propertyName == "Corrupted") {
+                  if (const bool* corruptedValue = std::get_if<bool>(&value);
+                      corruptedValue != nullptr) {
+                    corrupted = *corruptedValue;
+                  }
                 }
               }
 
@@ -2738,7 +2744,7 @@
                       asyncResp->strand_,
                       absl::AnyInvocable<void(const boost::system::error_code&,
                                               const std::vector<uint8_t>&)>(
-                          [asyncResp, rawId](
+                          [asyncResp, rawId, corrupted](
                               const boost::system::error_code& ec2,
                               const std::vector<uint8_t>& rawData) {
                             if (ec2) {
@@ -2757,6 +2763,10 @@
                               messages::internalError(asyncResp->res);
                               return;
                             }
+                            if (corrupted.has_value()) {
+                              asyncResp->res.jsonValue["Corrupted"] =
+                                  *corrupted;
+                            }
                             asyncResp->res.jsonValue["Status"]["State"] =
                                 "Enabled";
                             asyncResp->res.jsonValue["RawData"] = rawData;
diff --git a/test/redfish-core/lib/manager_test.cpp b/test/redfish-core/lib/manager_test.cpp
index c93dd77..5977dd8 100644
--- a/test/redfish-core/lib/manager_test.cpp
+++ b/test/redfish-core/lib/manager_test.cpp
@@ -9,6 +9,8 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include "absl/functional/any_invocable.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
 #include "http_request.hpp"
 #include "http_response.hpp"
 #include "async_resp.hpp"
@@ -34,6 +36,10 @@
 using ::managedStore::ManagedType;
 using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction;
 using ::managedStore::ValueType;
+using ::testing::_;
+using ::testing::An;
+using ::testing::Eq;
+using ::testing::NotNull;
 
 constexpr char kClassType[] = "Temperature";
 constexpr char kSensor[] = "sensor0";
@@ -735,6 +741,183 @@
   EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
 }
 
+void UpsertMockRawEepromProperties(
+    managedStore::MockSerializedManagedObjectStore& mock_store,
+    absl::string_view raw_id, uint32_t bus, uint32_t address, bool corrupted) {
+  const std::string object_path =
+      absl::StrCat("/xyz/openbmc_project/FruDevice/", raw_id);
+  KeyType mapper_key(
+      ManagedType::kManagedMapperObject, object_path,
+      std::vector<std::string>{"xyz.openbmc_project.Inventory.Item.I2CDevice"});
+  dbus::utility::MapperGetObject mapper_object = {
+      {"xyz.openbmc_project.FruDevice",
+       {"xyz.openbmc_project.Inventory.Item.I2CDevice"}}};
+  ASSERT_TRUE(
+      mock_store
+          .upsertMockObjectIntoManagedStore(
+              mapper_key, managedStore::MockManagedStoreTest::CreateValueType(
+                              mapper_object))
+          .ok());
+
+  KeyType properties_key(ManagedType::kManagedPropertyMap,
+                         "xyz.openbmc_project.FruDevice", object_path,
+                         "xyz.openbmc_project.Inventory.Item.I2CDevice");
+  DBusPropertiesMap properties = {
+      {"Bus", DbusVariantType(bus)},
+      {"Address", DbusVariantType(address)},
+      {"Corrupted", DbusVariantType(corrupted)},
+  };
+  ASSERT_TRUE(
+      mock_store
+          .upsertMockObjectIntoManagedStore(
+              properties_key,
+              managedStore::MockManagedStoreTest::CreateValueType(properties))
+          .ok());
+}
+
+// Tests that "Corrupted": true is included in the response when the EEPROM has
+// Corrupted set to true on D-Bus.
+TEST_F(SnapshotFixture,
+       HandleRawEepromMemberGetCorruptedTrueReturnsCorruptedField) {
+  auto* mock_store =
+      dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore());
+  ASSERT_THAT(mock_store, NotNull());
+  UpsertMockRawEepromProperties(*mock_store, /*raw_id=*/"22_80", /*bus=*/22,
+                                /*address=*/80, /*corrupted=*/true);
+
+  EXPECT_CALL(
+      *mock_store,
+      PostDbusCallToIoContextThreadSafe(
+          _,
+          An<absl::AnyInvocable<void(const boost::system::error_code&,
+                                     const std::vector<uint8_t>&)>&&>(),
+          "xyz.openbmc_project.FruDevice", "/xyz/openbmc_project/FruDevice",
+          "xyz.openbmc_project.FruDeviceManager", "GetRawFru", Eq(uint16_t{22}),
+          Eq(uint8_t{80})))
+      .WillOnce(
+          managedStore::
+              SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction<
+                  std::vector<uint8_t>>::
+                  SimulateSuccessfulAsyncPostDbusCallWithValue(
+                      std::make_shared<std::vector<uint8_t>>(
+                          std::vector<uint8_t>{1, 2, 3})));
+
+  handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, "22_80");
+
+  RunIoUntilDone();
+
+  EXPECT_EQ(share_async_resp_->res.jsonValue, nlohmann::json::parse(R"json({
+    "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/22_80",
+    "@odata.type": "#GoogleFruDevice.v1_0_0.RawEeprom",
+    "Id": "22_80",
+    "Name": "Google Raw EEPROM",
+    "Bus": 22,
+    "Address": 80,
+    "Corrupted": true,
+    "Status": {
+      "State": "Enabled"
+    },
+    "RawData": [1, 2, 3],
+    "HexdumpFormattedRawData": "0000:  01 02 03                                          | ... |\n"
+  })json"));
+  EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
+}
+
+// Tests that "Corrupted": false is included in the response when the EEPROM has
+// Corrupted set to false on D-Bus.
+TEST_F(SnapshotFixture,
+       HandleRawEepromMemberGetCorruptedFalseReturnsCorruptedField) {
+  auto* mock_store =
+      dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore());
+  ASSERT_THAT(mock_store, NotNull());
+  UpsertMockRawEepromProperties(*mock_store, /*raw_id=*/"22_80", /*bus=*/22,
+                                /*address=*/80, /*corrupted=*/false);
+
+  EXPECT_CALL(
+      *mock_store,
+      PostDbusCallToIoContextThreadSafe(
+          _,
+          An<absl::AnyInvocable<void(const boost::system::error_code&,
+                                     const std::vector<uint8_t>&)>&&>(),
+          "xyz.openbmc_project.FruDevice", "/xyz/openbmc_project/FruDevice",
+          "xyz.openbmc_project.FruDeviceManager", "GetRawFru", Eq(uint16_t{22}),
+          Eq(uint8_t{80})))
+      .WillOnce(
+          managedStore::
+              SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction<
+                  std::vector<uint8_t>>::
+                  SimulateSuccessfulAsyncPostDbusCallWithValue(
+                      std::make_shared<std::vector<uint8_t>>(
+                          std::vector<uint8_t>{1, 2, 3})));
+
+  handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, "22_80");
+
+  RunIoUntilDone();
+
+  EXPECT_EQ(share_async_resp_->res.jsonValue, nlohmann::json::parse(R"json({
+    "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/22_80",
+    "@odata.type": "#GoogleFruDevice.v1_0_0.RawEeprom",
+    "Id": "22_80",
+    "Name": "Google Raw EEPROM",
+    "Bus": 22,
+    "Address": 80,
+    "Corrupted": false,
+    "Status": {
+      "State": "Enabled"
+    },
+    "RawData": [1, 2, 3],
+    "HexdumpFormattedRawData": "0000:  01 02 03                                          | ... |\n"
+  })json"));
+  EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
+}
+
+// Tests that "Corrupted" is omitted when GetRawFru fails with invalid_argument
+// (State: "Disabled") even if Corrupted is false on D-Bus.
+TEST_F(SnapshotFixture,
+       HandleRawEepromMemberGetNotPopulatedOmitsCorruptedField) {
+  auto* mock_store =
+      dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore());
+  ASSERT_THAT(mock_store, NotNull());
+  UpsertMockRawEepromProperties(*mock_store, /*raw_id=*/"22_80", /*bus=*/22,
+                                /*address=*/80, /*corrupted=*/false);
+
+  EXPECT_CALL(
+      *mock_store,
+      PostDbusCallToIoContextThreadSafe(
+          _,
+          An<absl::AnyInvocable<void(const boost::system::error_code&,
+                                     const std::vector<uint8_t>&)>&&>(),
+          "xyz.openbmc_project.FruDevice", "/xyz/openbmc_project/FruDevice",
+          "xyz.openbmc_project.FruDeviceManager", "GetRawFru", Eq(uint16_t{22}),
+          Eq(uint8_t{80})))
+      .WillOnce(
+          managedStore::
+              SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction::
+                  SimulateFailedAsyncPostDbusCallWithEmptyValue(
+                      boost::system::errc::make_error_code(
+                          boost::system::errc::invalid_argument)));
+
+  handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, "22_80");
+
+  RunIoUntilDone();
+
+  EXPECT_EQ(share_async_resp_->res.jsonValue, nlohmann::json::parse(R"json({
+    "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/22_80",
+    "@odata.type": "#GoogleFruDevice.v1_0_0.RawEeprom",
+    "Id": "22_80",
+    "Name": "Google Raw EEPROM",
+    "Bus": 22,
+    "Address": 80,
+    "Status": {
+      "State": "Disabled"
+    }
+  })json"));
+  EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
+}
+
 TEST_F(SnapshotFixture, handleRawEepromMemberGetZeroLength) {
   std::string rawId = "Eeprom1";
   KeyType key(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.FruDevice",