Handle unpopulated raw EEPROMs gracefully in the RawEeproms member GET handler.

Google-Bug-Id:555857465
PiperOrigin-RevId: 975934136
Change-Id: Idb63775d3b897a50b953aef407af2fa100d96edd
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index b1c6c68..ff0471d 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -2782,18 +2782,32 @@
                       asyncResp->strand_,
                       absl::AnyInvocable<void(const boost::system::error_code&,
                                               const std::vector<uint8_t>&)>(
-                          [asyncResp](const boost::system::error_code& ec2,
-                                      const std::vector<uint8_t>& rawData) {
+                          [asyncResp, rawId](
+                              const boost::system::error_code& ec2,
+                              const std::vector<uint8_t>& rawData) {
                             if (ec2) {
+                              if (ec2 ==
+                                  boost::system::errc::invalid_argument) {
+                                BMCWEB_LOG_WARNING
+                                    << "GetRawFru DBus call failed for "
+                                    << rawId
+                                    << " (EEPROM not populated): " << ec2;
+                                asyncResp->res.jsonValue["Status"]["State"] =
+                                    "Disabled";
+                                return;
+                              }
                               BMCWEB_LOG_ERROR << "GetRawFru DBus call failed: "
                                                << ec2;
                               messages::internalError(asyncResp->res);
                               return;
                             }
+                            asyncResp->res.jsonValue["Status"]["State"] =
+                                "Enabled";
                             asyncResp->res.jsonValue["RawData"] = rawData;
-                            asyncResp->res.jsonValue["HexdumpFormattedRawData"] =
-                          bytesToHexDump(rawData);
-                    }),
+                            asyncResp->res
+                                .jsonValue["HexdumpFormattedRawData"] =
+                                bytesToHexDump(rawData);
+                          }),
                       service, "/xyz/openbmc_project/FruDevice",
                       "xyz.openbmc_project.FruDeviceManager", "GetRawFru",
                       static_cast<uint16_t>(bus),
diff --git a/test/redfish-core/lib/manager_test.cpp b/test/redfish-core/lib/manager_test.cpp
index 115221d..f382ae1 100644
--- a/test/redfish-core/lib/manager_test.cpp
+++ b/test/redfish-core/lib/manager_test.cpp
@@ -32,6 +32,7 @@
 using ::dbus::utility::MapperServiceMap;
 using ::managedStore::KeyType;
 using ::managedStore::ManagedType;
+using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction;
 using ::managedStore::ValueType;
 
 constexpr char kClassType[] = "Temperature";
@@ -649,6 +650,9 @@
     "Name": "Google Raw EEPROM",
     "Bus": 2,
     "Address": 81,
+    "Status": {
+      "State": "Enabled"
+    },
     "RawData": [1, 2, 3],
     "HexdumpFormattedRawData": "0000:  01 02 03                                          | ... |\n"
   })"));
@@ -698,6 +702,7 @@
   RunIoUntilDone();
 
   nlohmann::json& json = share_async_resp_->res.jsonValue;
+  EXPECT_EQ(json["Status"]["State"], "Enabled");
   EXPECT_EQ(json["RawData"], std::vector<uint8_t>{});
   EXPECT_EQ(json["HexdumpFormattedRawData"], "");
   EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
@@ -750,6 +755,7 @@
   RunIoUntilDone();
 
   nlohmann::json& json = share_async_resp_->res.jsonValue;
+  EXPECT_EQ(json["Status"]["State"], "Enabled");
   EXPECT_EQ(json["RawData"], rawData);
 
   std::string expectedHexdump =
@@ -760,6 +766,107 @@
   EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
 }
 
+TEST_F(SnapshotFixture, handleRawEepromMemberGetNotPopulated) {
+  std::string rawId = "Eeprom1";
+  KeyType key(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.FruDevice",
+              "/xyz/openbmc_project/FruDevice/" + rawId,
+              "xyz.openbmc_project.Inventory.Item.I2CDevice");
+
+  DBusPropertiesMap props = {
+      {std::make_pair("Bus", DbusVariantType(static_cast<uint32_t>(2)))},
+      {std::make_pair("Address", DbusVariantType(static_cast<uint32_t>(81)))},
+  };
+
+  ASSERT_TRUE(
+      dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore())
+          ->upsertMockObjectIntoManagedStore(
+              key, managedStore::MockManagedStoreTest::CreateValueType(props))
+          .ok());
+
+  EXPECT_CALL(
+      *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore()),
+      PostDbusCallToIoContextThreadSafe(
+          testing::_,
+          testing::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",
+          testing::Eq(static_cast<uint16_t>(2)),
+          testing::Eq(static_cast<uint8_t>(81))))
+      .WillOnce(
+          managedStore::
+              SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction::
+                  SimulateFailedAsyncPostDbusCallWithEmptyValue(
+                      boost::system::errc::make_error_code(
+                          boost::system::errc::invalid_argument)));
+
+  handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, rawId);
+
+  RunIoUntilDone();
+
+  nlohmann::json& json = share_async_resp_->res.jsonValue;
+  EXPECT_EQ(json, nlohmann::json::parse(R"({
+    "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/Eeprom1",
+    "@odata.type": "#GoogleFruDevice.v1_0_0.RawEeprom",
+    "Id": "Eeprom1",
+    "Name": "Google Raw EEPROM",
+    "Bus": 2,
+    "Address": 81,
+    "Status": {
+      "State": "Disabled"
+    }
+  })"));
+  EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
+}
+
+TEST_F(SnapshotFixture, handleRawEepromMemberGetInternalError) {
+  std::string rawId = "Eeprom1";
+  KeyType key(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.FruDevice",
+              "/xyz/openbmc_project/FruDevice/" + rawId,
+              "xyz.openbmc_project.Inventory.Item.I2CDevice");
+
+  DBusPropertiesMap props = {
+      {std::make_pair("Bus", DbusVariantType(static_cast<uint32_t>(2)))},
+      {std::make_pair("Address", DbusVariantType(static_cast<uint32_t>(81)))},
+  };
+
+  ASSERT_TRUE(
+      dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore())
+          ->upsertMockObjectIntoManagedStore(
+              key, managedStore::MockManagedStoreTest::CreateValueType(props))
+          .ok());
+
+  EXPECT_CALL(
+      *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
+          managedStore::GetManagedObjectStore()),
+      PostDbusCallToIoContextThreadSafe(
+          testing::_,
+          testing::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",
+          testing::Eq(static_cast<uint16_t>(2)),
+          testing::Eq(static_cast<uint8_t>(81))))
+      .WillOnce(
+          managedStore::
+              SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction::
+                  SimulateFailedAsyncPostDbusCallWithEmptyValue(
+                      boost::system::errc::make_error_code(
+                          boost::system::errc::io_error)));
+
+  handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, rawId);
+
+  RunIoUntilDone();
+
+  EXPECT_EQ(share_async_resp_->res.result(),
+            boost::beast::http::status::internal_server_error);
+}
+
 TEST_F(SnapshotFixture, handleRawEepromMemberGetNotFound) {
   handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_,
                            "NonExistentEeprom");