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");