| #include <cstdint> | |
| #include <filesystem> //NOLINT | |
| #include <memory> | |
| #include <string> | |
| #include <system_error> // NOLINT | |
| #include <utility> | |
| #include <vector> | |
| #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" | |
| #include "dbus_utility.hpp" | |
| #include "managers.hpp" | |
| #include "test/redfish-core/lib/snapshot_fixture.hpp" | |
| #include <nlohmann/json.hpp> | |
| #include "managed_store.hpp" | |
| #include "managed_store_types.hpp" | |
| #include "test/g3/mock_managed_store.hpp" | |
| #include "test/g3/mock_managed_store_test.hpp" | |
| namespace redfish | |
| { | |
| namespace | |
| { | |
| using ::dbus::utility::DBusPropertiesMap; | |
| using ::dbus::utility::DbusVariantType; | |
| using ::dbus::utility::MapperGetSubTreeResponse; | |
| using ::dbus::utility::MapperServiceMap; | |
| using ::managedStore::KeyType; | |
| 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"; | |
| constexpr double kInput = 43.0; | |
| constexpr double kOutput = 4000.0; | |
| constexpr double kSetpoint = 65.0; | |
| constexpr uint8_t kTestData = 15; | |
| // std::shared_ptr<ValueType> CreateMockSubtreeResponse() | |
| // { | |
| // MapperGetSubTreeResponse mockSubtreeResponse{{std::make_pair( | |
| // "/xyz/openbmc_project/inventory/system/component/BMC_flash", | |
| // MapperServiceMap{{std::make_pair( | |
| // "xyz.openbmc_project.EntityManager", | |
| // std::vector<std::string>{ | |
| // "xyz.openbmc_project.Inventory.Decorator.LocationCode"})}})}}; | |
| // return managedStore::MockManagedStoreTest::CreateValueType( | |
| // std::move(mockSubtreeResponse)); | |
| // } | |
| // TODO(edwarddl): Uncomment after handleManagerGet is updated | |
| // TEST_F(SnapshotFixture, handleManagerGetTest) | |
| // { | |
| // KeyType key(ManagedType::kManagedSubtree, | |
| // "/xyz/openbmc_project/inventory", 0, | |
| // {"xyz.openbmc_project.Inventory.Item.Bmc"}); | |
| // ASSERT_TRUE( | |
| // dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| // managedStore::GetManagedObjectStore()) | |
| // ->upsertMockObjectIntoManagedStore( | |
| // key, CreateMockSubtreeResponse()) | |
| // .ok()); | |
| // handleManagerGet(app_, CreateRequest(), share_async_resp_); | |
| // | |
| // RunIoUntilDone(); | |
| // | |
| // nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| // | |
| // LOG(INFO) << json.dump(2); | |
| // EXPECT_EQ(json["@odata.id"], "/redfish/v1/Managers/bmc"); | |
| // EXPECT_EQ(json["Location"]["PartLocation"]["ServiceLabel"], "BMC"); | |
| // EXPECT_EQ(json["Location"]["PartLocation"]["LocationType"], "Embedded"); | |
| // EXPECT_EQ(json["Location"]["PartLocationContext"], "DC_SCM"); | |
| // EXPECT_EQ(json["Location"]["Oem"]["Google"]["EmbeddedLocationContext"], | |
| // "openbmc_manager"); | |
| // EXPECT_EQ(json["Links"]["ManagerForServers@odata.count"], 1); | |
| // EXPECT_EQ(json["Links"]["ManagerForServers"][0]["@odata.id"], | |
| // "/redfish/v1/Systems/system"); | |
| // EXPECT_EQ(share_async_resp_->res.result(), | |
| // boost::beast::http::status::ok); | |
| // } | |
| std::shared_ptr<ValueType> CreatePidDebugInfoProperty() | |
| { | |
| DBusPropertiesMap pidDebugInfoProperty{ | |
| {std::make_pair("ClassType", DbusVariantType(kClassType))}, | |
| {std::make_pair("Input", DbusVariantType(kInput))}, | |
| {std::make_pair("Leader", DbusVariantType(kSensor))}, | |
| {std::make_pair("Output", DbusVariantType(kOutput))}, | |
| {std::make_pair("Setpoint", DbusVariantType(kSetpoint))}, | |
| {std::make_pair("TestData", DbusVariantType(kTestData))}}; | |
| return managedStore::MockManagedStoreTest::CreateValueType( | |
| std::move(pidDebugInfoProperty)); | |
| } | |
| TEST_F(SnapshotFixture, updateZoneLeaderInfoGetNull) | |
| { | |
| const std::string zoneIndex = "0"; | |
| const std::string name = "Zone_0"; | |
| const std::string leader = "sensor_PID"; | |
| const std::string pidDebugInfoPath = | |
| "/xyz/openbmc_project/settings/fanctrl/zone" + zoneIndex + "/" + leader; | |
| auto response = std::make_shared<bmcweb::AsyncResp>(); | |
| nlohmann::json& json = response->res.jsonValue; | |
| managedStore::ManagedObjectStoreContext context(response); | |
| // Test for null dbus response | |
| updateZoneLeaderInfo(response, zoneIndex, name, leader, context); | |
| RunIoUntilDone(); | |
| EXPECT_TRUE( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["ClassType"] | |
| .is_null()); | |
| EXPECT_TRUE( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Input"] | |
| .is_null()); | |
| EXPECT_TRUE( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Output"] | |
| .is_null()); | |
| EXPECT_TRUE( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Sensor"] | |
| .is_null()); | |
| EXPECT_TRUE( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Setpoint"] | |
| .is_null()); | |
| } | |
| TEST_F(SnapshotFixture, updateZoneLeaderInfoSuccess) | |
| { | |
| const std::string zoneIndex = "0"; | |
| const std::string name = "Zone_0"; | |
| const std::string leader = "sensor_PID"; | |
| const std::string pidDebugInfoPath = | |
| "/xyz/openbmc_project/settings/fanctrl/zone" + zoneIndex + "/" + leader; | |
| auto response = std::make_shared<bmcweb::AsyncResp>(); | |
| nlohmann::json& json = response->res.jsonValue; | |
| managedStore::ManagedObjectStoreContext context(response); | |
| // kManagedPropertyMap | |
| KeyType key(ManagedType::kManagedPropertyMap, | |
| "xyz.openbmc_project.State.FanCtrl", pidDebugInfoPath, | |
| "xyz.openbmc_project.Debug.Pid.ThermalPower"); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, CreatePidDebugInfoProperty()) | |
| .ok()); | |
| updateZoneLeaderInfo(response, zoneIndex, name, leader, context); | |
| RunIoUntilDone(); | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["ClassType"], | |
| kClassType); | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Input"], | |
| kInput); | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Sensor"], | |
| kSensor); | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Output"], | |
| kOutput); | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["Setpoint"], | |
| kSetpoint); | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][name]["Leader"]["TestData"], | |
| "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( | |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()), | |
| PostDbusCallToIoContextThreadSafe( | |
| testing::_, | |
| testing::An< | |
| absl::AnyInvocable<void(const boost::system::error_code&)>&&>(), | |
| "xyz.openbmc_project.State.Chassis", testing::_, | |
| "org.freedesktop.DBus.Properties", "Set", | |
| "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", | |
| testing::_)) | |
| .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")); | |
| } | |
| // TODO(edwarddl): Uncomment after handleManagerGet is updated | |
| // TEST_F(SnapshotFixture, handleManagerGetMultiSystem) | |
| // { | |
| // KeyType key(ManagedType::kManagedSubtreePaths, "/", 0, | |
| // {"xyz.openbmc_project.Inventory.Item.System"}); | |
| // | |
| // std::vector<std::string> path = { | |
| // "/xyz/system1", | |
| // "/xyz/system2", | |
| // }; | |
| // std::shared_ptr<ValueType> test_value = CreateValueType(path); | |
| // ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| // managedStore::GetManagedObjectStore()) | |
| // ->upsertMockObjectIntoManagedStore(key, test_value) | |
| // .ok()); | |
| // | |
| // handleManagerGet(app_, CreateRequest(), share_async_resp_); | |
| // | |
| // RunIoUntilDone(); | |
| // | |
| // nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| // | |
| // EXPECT_EQ(json["Links"]["ManagerForServers@odata.count"], 2); | |
| // EXPECT_EQ(json["Links"]["ManagerForServers"][0]["@odata.id"], | |
| // "/redfish/v1/Systems/system1"); | |
| // EXPECT_EQ(json["Links"]["ManagerForServers"][1]["@odata.id"], | |
| // "/redfish/v1/Systems/system2"); | |
| // EXPECT_EQ(share_async_resp_->res.result(), | |
| // boost::beast::http::status::ok); | |
| // } | |
| TEST_F(SnapshotFixture, handleManagerGetFruDeviceOemLink) { | |
| std::error_code ec; | |
| auto origPath = std::filesystem::current_path(ec); | |
| std::filesystem::current_path(std::filesystem::temp_directory_path(ec), ec); | |
| handleManagerGet(app_, CreateRequest(), share_async_resp_, "bmc"); | |
| RunIoUntilDone(); | |
| std::filesystem::current_path(origPath, ec); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["Oem"]["Google"]["FruDevice"]["@odata.id"], | |
| "/redfish/v1/Managers/bmc/Oem/Google/FruDevice"); | |
| } | |
| TEST_F(SnapshotFixture, handleFruDeviceGet) { | |
| handleFruDeviceGet(app_, CreateRequest(), share_async_resp_); | |
| 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", | |
| "@odata.type": "#GoogleFruDevice.v1_0_0.GoogleFruDeviceService", | |
| "Id": "FruDevice", | |
| "IpmiFrus": { | |
| "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/IpmiFrus" | |
| }, | |
| "Name": "Google FRU Device Service", | |
| "RawEeproms": { | |
| "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms" | |
| } | |
| })")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(SnapshotFixture, handleIpmiFruCollectionGet) { | |
| KeyType key(ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/FruDevice", 0, | |
| {"xyz.openbmc_project.FruDevice"}); | |
| std::vector<std::string> paths = { | |
| "/xyz/openbmc_project/FruDevice/TestFru1", | |
| "/xyz/openbmc_project/FruDevice/TestFru2", | |
| }; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType(paths)) | |
| .ok()); | |
| handleIpmiFruCollectionGet(app_, CreateRequest(), share_async_resp_); | |
| 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/IpmiFrus", | |
| "@odata.type": "#GoogleFruDevice.v1_0_0.GoogleIpmiFruCollection", | |
| "Id": "IpmiFrus", | |
| "Members": [ | |
| { | |
| "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/IpmiFrus/TestFru1" | |
| }, | |
| { | |
| "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/IpmiFrus/TestFru2" | |
| } | |
| ], | |
| "Members@odata.count": 2, | |
| "Name": "Google IPMI FRU Collection" | |
| })")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(SnapshotFixture, handleRawEepromCollectionGet) { | |
| KeyType key(ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/FruDevice", 0, | |
| {"xyz.openbmc_project.Inventory.Item.I2CDevice"}); | |
| std::vector<std::string> paths = { | |
| "/xyz/openbmc_project/FruDevice/Eeprom1", | |
| }; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType(paths)) | |
| .ok()); | |
| handleRawEepromCollectionGet(app_, CreateRequest(), share_async_resp_); | |
| 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", | |
| "@odata.type": "#GoogleFruDevice.v1_0_0.GoogleRawEepromCollection", | |
| "Id": "RawEeproms", | |
| "Members": [ | |
| { | |
| "@odata.id": "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/Eeprom1" | |
| } | |
| ], | |
| "Members@odata.count": 1, | |
| "Name": "Google Raw EEPROM Collection" | |
| })")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST(ToTitleCaseTest, ConvertsPropertyNamesToTitleCase) { | |
| EXPECT_EQ(toTitleCase("BOARD_PRODUCT_NAME"), "BoardProductName"); | |
| EXPECT_EQ(toTitleCase("BUS"), "Bus"); | |
| EXPECT_EQ(toTitleCase("ADDRESS"), "Address"); | |
| EXPECT_EQ(toTitleCase("PRODUCT_MANUFACTURER"), "ProductManufacturer"); | |
| EXPECT_EQ(toTitleCase("PRODUCT_SERIAL_NUMBER"), "ProductSerialNumber"); | |
| EXPECT_EQ(toTitleCase("foo_bar_baz"), "FooBarBaz"); | |
| EXPECT_EQ(toTitleCase(""), ""); | |
| } | |
| // Tests handleIpmiFruMemberGet with dynamic ObjectMapper service discovery: | |
| // 1. Registers a mock Mapper GetObject response (kManagedMapperObject) mapping | |
| // the FRU path to its owning service ("xyz.openbmc_project.FruDevice"). | |
| // 2. Registers mock D-Bus properties (kManagedPropertyMap) on that service. | |
| // 3. Verifies that handleIpmiFruMemberGet queries the discovered service and | |
| // populates the Redfish response correctly. | |
| TEST_F(SnapshotFixture, handleIpmiFruMemberGet) { | |
| std::string fruId = "TestFru1"; | |
| KeyType objKey(ManagedType::kManagedMapperObject, | |
| "/xyz/openbmc_project/FruDevice/" + fruId, | |
| std::vector<std::string>{"xyz.openbmc_project.FruDevice"}); | |
| dbus::utility::MapperGetObject objVal = { | |
| {"xyz.openbmc_project.FruDevice", {"xyz.openbmc_project.FruDevice"}}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| objKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(objVal)) | |
| .ok()); | |
| KeyType key(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.FruDevice", | |
| "/xyz/openbmc_project/FruDevice/" + fruId, | |
| "xyz.openbmc_project.FruDevice"); | |
| DBusPropertiesMap props = { | |
| {std::make_pair("BUS", DbusVariantType(static_cast<uint32_t>(1)))}, | |
| {std::make_pair("ADDRESS", DbusVariantType(static_cast<uint32_t>(80)))}, | |
| {std::make_pair("BOARD_PRODUCT_NAME", DbusVariantType("BoardName"))}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType(props)) | |
| .ok()); | |
| handleIpmiFruMemberGet(app_, CreateRequest(), share_async_resp_, fruId); | |
| 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/IpmiFrus/TestFru1", | |
| "@odata.type": "#GoogleFruDevice.v1_0_0.IpmiFru", | |
| "Id": "TestFru1", | |
| "Name": "Google IPMI FRU", | |
| "Bus": 1, | |
| "Address": 80, | |
| "BoardProductName": "BoardName" | |
| })")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| // Tests handleIpmiFruMemberGet when the requested FRU ID does not exist in | |
| // the ObjectMapper, verifying that HTTP 404 (ResourceNotFound) is returned. | |
| TEST_F(SnapshotFixture, handleIpmiFruMemberGetNotFound) { | |
| handleIpmiFruMemberGet(app_, CreateRequest(), share_async_resp_, | |
| "NonExistentFru"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| // Tests end-to-end HTTP request dispatch through Crow router to both IpmiFrus | |
| // and RawEeproms member endpoints: | |
| // 1. Verifies that the Crow router dispatches GET requests for /IpmiFrus/<id> | |
| // and /RawEeproms/<id> (without trailing slashes) correctly. | |
| // 2. Verifies dynamic ObjectMapper resolution (kManagedMapperObject) and | |
| // properties population for IpmiFrus. | |
| // 3. Verifies dynamic ObjectMapper resolution and GetRawFru D-Bus method call | |
| // mock invocation for RawEeproms. | |
| TEST_F(SnapshotFixture, requestRoutesFruDevicesRouteMatching) { | |
| requestRoutesFruDevices(app_); | |
| app_.validate(); | |
| std::string fruId = "TestFru1"; | |
| KeyType fruObjKey(ManagedType::kManagedMapperObject, | |
| "/xyz/openbmc_project/FruDevice/" + fruId, | |
| std::vector<std::string>{"xyz.openbmc_project.FruDevice"}); | |
| dbus::utility::MapperGetObject fruObjVal = { | |
| {"xyz.openbmc_project.FruDevice", {"xyz.openbmc_project.FruDevice"}}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| fruObjKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(fruObjVal)) | |
| .ok()); | |
| KeyType key(ManagedType::kManagedPropertyMap, "xyz.openbmc_project.FruDevice", | |
| "/xyz/openbmc_project/FruDevice/" + fruId, | |
| "xyz.openbmc_project.FruDevice"); | |
| DBusPropertiesMap props = { | |
| {std::make_pair("BUS", DbusVariantType(static_cast<uint32_t>(1)))}, | |
| {std::make_pair("ADDRESS", DbusVariantType(static_cast<uint32_t>(80)))}, | |
| {std::make_pair("BOARD_PRODUCT_NAME", DbusVariantType("BoardName"))}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType(props)) | |
| .ok()); | |
| boost::beast::http::request<boost::beast::http::string_body> reqIn{ | |
| boost::beast::http::verb::get, | |
| "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/IpmiFrus/TestFru1", 11}; | |
| std::error_code ec; | |
| crow::Request req(reqIn, ec); | |
| auto async_resp = std::make_shared<bmcweb::AsyncResp>(); | |
| app_.handle(req, async_resp); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(async_resp->res.result(), boost::beast::http::status::ok); | |
| EXPECT_EQ(async_resp->res.jsonValue["@odata.id"], | |
| "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/IpmiFrus/TestFru1"); | |
| EXPECT_EQ(async_resp->res.jsonValue["Id"], "TestFru1"); | |
| // Verify RawEeproms member route with dynamic ObjectMapper resolution | |
| std::string rawId = "Eeprom1"; | |
| KeyType rawObjKey( | |
| ManagedType::kManagedMapperObject, | |
| "/xyz/openbmc_project/FruDevice/" + rawId, | |
| std::vector<std::string>{ | |
| "xyz.openbmc_project.Inventory.Item.I2CDevice"}); | |
| dbus::utility::MapperGetObject rawObjVal = { | |
| {"xyz.openbmc_project.FruDevice", | |
| {"xyz.openbmc_project.Inventory.Item.I2CDevice"}}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| rawObjKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(rawObjVal)) | |
| .ok()); | |
| KeyType rawKey(ManagedType::kManagedPropertyMap, | |
| "xyz.openbmc_project.FruDevice", | |
| "/xyz/openbmc_project/FruDevice/" + rawId, | |
| "xyz.openbmc_project.Inventory.Item.I2CDevice"); | |
| DBusPropertiesMap rawProps = { | |
| {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( | |
| rawKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(rawProps)) | |
| .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:: | |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< | |
| std::vector<uint8_t>>:: | |
| SimulateSuccessfulAsyncPostDbusCallWithValue( | |
| std::make_shared<std::vector<uint8_t>>( | |
| std::vector<uint8_t>{0x01, 0x02, 0x03}))); | |
| boost::beast::http::request<boost::beast::http::string_body> rawReqIn{ | |
| boost::beast::http::verb::get, | |
| "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/Eeprom1", 11}; | |
| crow::Request rawReq(rawReqIn, ec); | |
| auto raw_async_resp = std::make_shared<bmcweb::AsyncResp>(); | |
| app_.handle(rawReq, raw_async_resp); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(raw_async_resp->res.result(), boost::beast::http::status::ok); | |
| EXPECT_EQ(raw_async_resp->res.jsonValue["@odata.id"], | |
| "/redfish/v1/Managers/bmc/Oem/Google/FruDevice/RawEeproms/Eeprom1"); | |
| EXPECT_EQ(raw_async_resp->res.jsonValue["Id"], "Eeprom1"); | |
| } | |
| // Tests handleRawEepromMemberGet with dynamic ObjectMapper service discovery: | |
| // 1. Registers mock Mapper GetObject mapping (kManagedMapperObject) for I2CDevice. | |
| // 2. Registers Bus/Address properties on the discovered service. | |
| // 3. Expects GetRawFru D-Bus call to be issued to the discovered service. | |
| TEST_F(SnapshotFixture, handleRawEepromMemberGet) { | |
| std::string rawId = "Eeprom1"; | |
| KeyType rawObjKey( | |
| ManagedType::kManagedMapperObject, | |
| "/xyz/openbmc_project/FruDevice/" + rawId, | |
| std::vector<std::string>{ | |
| "xyz.openbmc_project.Inventory.Item.I2CDevice"}); | |
| dbus::utility::MapperGetObject rawObjVal = { | |
| {"xyz.openbmc_project.FruDevice", | |
| {"xyz.openbmc_project.Inventory.Item.I2CDevice"}}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| rawObjKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(rawObjVal)) | |
| .ok()); | |
| 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:: | |
| 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_, 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": "Enabled" | |
| }, | |
| "RawData": [1, 2, 3], | |
| "HexdumpFormattedRawData": "0000: 01 02 03 | ... |\n" | |
| })")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| // Tests handleRawEepromMemberGet on 64-bit platforms (e.g., aarch64), | |
| // where FruDevice registers Bus and Address properties as uint64_t (size_t) | |
| // rather than uint32_t. | |
| TEST_F(SnapshotFixture, handleRawEepromMemberGetUint64) { | |
| std::string rawId = "Eeprom1"; | |
| KeyType rawObjKey( | |
| ManagedType::kManagedMapperObject, | |
| "/xyz/openbmc_project/FruDevice/" + rawId, | |
| std::vector<std::string>{ | |
| "xyz.openbmc_project.Inventory.Item.I2CDevice"}); | |
| dbus::utility::MapperGetObject rawObjVal = { | |
| {"xyz.openbmc_project.FruDevice", | |
| {"xyz.openbmc_project.Inventory.Item.I2CDevice"}}}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| rawObjKey, | |
| managedStore::MockManagedStoreTest::CreateValueType(rawObjVal)) | |
| .ok()); | |
| 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<uint64_t>(2)))}, | |
| {std::make_pair("Address", DbusVariantType(static_cast<uint64_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:: | |
| 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_, 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": "Enabled" | |
| }, | |
| "RawData": [1, 2, 3], | |
| "HexdumpFormattedRawData": "0000: 01 02 03 | ... |\n" | |
| })")); | |
| 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", | |
| "/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:: | |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< | |
| std::vector<uint8_t>>:: | |
| SimulateSuccessfulAsyncPostDbusCallWithValue( | |
| std::make_shared<std::vector<uint8_t>>( | |
| std::vector<uint8_t>{}))); | |
| handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, rawId); | |
| 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); | |
| } | |
| TEST_F(SnapshotFixture, handleRawEepromMemberGetMultipleLines) { | |
| 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()); | |
| std::vector<uint8_t> rawData; | |
| for (int i = 0; i < 20; ++i) { | |
| rawData.push_back(static_cast<uint8_t>('A' + i)); | |
| } | |
| 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:: | |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< | |
| std::vector<uint8_t>>:: | |
| SimulateSuccessfulAsyncPostDbusCallWithValue( | |
| std::make_shared<std::vector<uint8_t>>(rawData))); | |
| handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, rawId); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["Status"]["State"], "Enabled"); | |
| EXPECT_EQ(json["RawData"], rawData); | |
| std::string expectedHexdump = | |
| "0000: 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 | " | |
| "ABCDEFGHIJKLMNOP |\n" | |
| "0010: 51 52 53 54 | QRST |\n"; | |
| EXPECT_EQ(json["HexdumpFormattedRawData"], expectedHexdump); | |
| 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"); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| TEST_F(SnapshotFixture, handleIpmiFruCollectionGetInvalidOdataVersion) { | |
| boost::beast::http::request<boost::beast::http::string_body> reqIn; | |
| reqIn.set("OData-Version", "3.0"); | |
| std::error_code ec; | |
| crow::Request req(reqIn, ec); | |
| handleIpmiFruCollectionGet(app_, req, share_async_resp_); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::precondition_failed); | |
| } | |
| TEST_F(SnapshotFixture, handleRawEepromCollectionGetInvalidOdataVersion) { | |
| boost::beast::http::request<boost::beast::http::string_body> reqIn; | |
| reqIn.set("OData-Version", "3.0"); | |
| std::error_code ec; | |
| crow::Request req(reqIn, ec); | |
| handleRawEepromCollectionGet(app_, req, share_async_resp_); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::precondition_failed); | |
| } | |
| TEST_F(SnapshotFixture, handleIpmiFruMemberGetInvalidId) { | |
| std::string fruId = "Test-Fru"; | |
| handleIpmiFruMemberGet(app_, CreateRequest(), share_async_resp_, fruId); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| TEST_F(SnapshotFixture, handleRawEepromMemberGetInvalidId) { | |
| std::string rawId = "Eeprom.1"; | |
| handleRawEepromMemberGet(app_, CreateRequest(), share_async_resp_, rawId); | |
| RunIoUntilDone(); | |
| EXPECT_EQ(share_async_resp_->res.result(), | |
| boost::beast::http::status::not_found); | |
| } | |
| TEST_F(SnapshotFixture, asyncPopulatePidZoneChassisValid) { | |
| const std::string connection = "xyz.openbmc_project.EntityManager"; | |
| const std::string path = "/xyz/openbmc_project/inventory"; | |
| const std::string zoneName = "Zone_0"; | |
| const std::string chassisName = "TestChassis"; | |
| // Mock ManagedObjectType for asyncPopulatePid | |
| dbus::utility::ManagedObjectType managedObj = { | |
| {sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/" + chassisName + | |
| "/" + zoneName), | |
| {{"xyz.openbmc_project.Configuration.Pid.Zone", | |
| {{"Name", DbusVariantType(zoneName)}, | |
| {"Class", DbusVariantType("temp")}, | |
| {"ZoneIndex", DbusVariantType(0.0)}, | |
| {"MinThermalOutput", DbusVariantType(3000.0)}}}}}}; | |
| KeyType objKey(ManagedType::kManagedObject, connection, path); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| objKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| managedObj)) | |
| .ok()); | |
| // Mock chassis subtree paths containing the matching chassis | |
| std::vector<std::string> chassisPaths = { | |
| "/xyz/openbmc_project/inventory/system/chassis/" + chassisName, | |
| }; | |
| KeyType chassisSubtreeKey( | |
| ManagedType::kManagedSubtreePaths, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisSubtreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| chassisPaths)) | |
| .ok()); | |
| asyncPopulatePid(connection, path, "", {}, share_async_resp_); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][zoneName]["Chassis"]["@odata.id"], | |
| "/redfish/v1/Chassis/" + chassisName); | |
| } | |
| TEST_F(SnapshotFixture, asyncPopulatePidZoneChassisInvalid) { | |
| const std::string connection = "xyz.openbmc_project.EntityManager"; | |
| const std::string path = "/xyz/openbmc_project/inventory"; | |
| const std::string zoneName = "Zone_0"; | |
| const std::string chassisName = "InvalidChassis"; | |
| // Mock ManagedObjectType with an invalid chassis name in the path | |
| dbus::utility::ManagedObjectType managedObj = { | |
| {sdbusplus::message::object_path( | |
| "/xyz/openbmc_project/inventory/system/chassis/" + chassisName + | |
| "/" + zoneName), | |
| {{"xyz.openbmc_project.Configuration.Pid.Zone", | |
| {{"Name", DbusVariantType(zoneName)}, | |
| {"Class", DbusVariantType("temp")}, | |
| {"ZoneIndex", DbusVariantType(0.0)}, | |
| {"MinThermalOutput", DbusVariantType(3000.0)}}}}}}; | |
| KeyType objKey(ManagedType::kManagedObject, connection, path); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| objKey, managedStore::MockManagedStoreTest::CreateValueType( | |
| managedObj)) | |
| .ok()); | |
| // Mock chassis subtree paths containing only OtherChassis (not InvalidChassis) | |
| std::vector<std::string> chassisPaths = { | |
| "/xyz/openbmc_project/inventory/system/chassis/OtherChassis", | |
| }; | |
| KeyType chassisSubtreeKey( | |
| ManagedType::kManagedSubtreePaths, "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Board", | |
| "xyz.openbmc_project.Inventory.Item.Chassis"}); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| chassisSubtreeKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| chassisPaths)) | |
| .ok()); | |
| asyncPopulatePid(connection, path, "", {}, share_async_resp_); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| // When chassis is invalid, Chassis property should not be reported | |
| EXPECT_FALSE( | |
| json["Oem"]["OpenBmc"]["Fan"]["FanZones"][zoneName].contains("Chassis")); | |
| } | |
| } // namespace | |
| } // namespace redfish |