| #include "app.hpp" |
| #include "async_resp.hpp" |
| #include "dbus_utility.hpp" |
| #include "event_service_manager.hpp" |
| #include "health.hpp" |
| #include "log_services.hpp" |
| #include "macros.hpp" |
| #include "snapshot_fixture.hpp" |
| #include "test/g3/mock_managed_store_test.hpp" |
| |
| #include <nlohmann/json.hpp> |
| |
| #include <map> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| namespace redfish |
| { |
| namespace |
| { |
| |
| using ::dbus::utility::DBusInteracesMap; |
| using ::dbus::utility::DBusPropertiesMap; |
| using ::dbus::utility::DbusVariantType; |
| using ::dbus::utility::ManagedObjectType; |
| using ::dbus::utility::MapperGetSubTreePathsResponse; |
| using ::managedStore::KeyType; |
| using ::managedStore::ManagedObjectStoreContext; |
| using ::managedStore::ManagedType; |
| using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeAction; |
| using ::managedStore:: |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction; |
| using ::managedStore::SimulateFailedAsyncSetPropertyDbusCallAction; |
| using ::managedStore::SimulateSuccessfulAsyncPostDbusCallThreadSafeAction; |
| using ::managedStore:: |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction; |
| using ::managedStore::SimulateSuccessfulAsyncSetPropertyDbusCallAction; |
| using ::managedStore::ValueType; |
| using ::testing::_; |
| using ::testing::An; |
| using PostPackageRepairStatusParam = std::vector< |
| std::tuple<uint16_t, uint16_t, uint16_t, uint16_t, std::vector<uint16_t>>>; |
| |
| const uint64_t BMC_DUMP_SIZE = 10; |
| |
| TEST(LogServicesDumpServiceTest, AllDumpTypesAreReturnedAsCorrectStrings) |
| { |
| std::map<DumpType, std::string_view> dumpTypeMap = { |
| {DumpType::BMC_DUMP, "BMC"}, |
| {DumpType::SYSTEM_DUMP, "System"}, |
| {DumpType::BMC_FAULT_LOG, "FaultLog"}, |
| {DumpType::SYSTEM_FAULT_LOG, "FaultLog"}, |
| }; |
| |
| for (size_t dumpIndex = 0; dumpIndex < dumpTypeMap.size(); ++dumpIndex) |
| { |
| DumpType dumpType = static_cast<DumpType>(dumpIndex); |
| EXPECT_EQ(dumpTypeToString(dumpType), dumpTypeMap[dumpType]); |
| } |
| } |
| |
| std::shared_ptr<ValueType> CreateMockFaultLogEntry(){ |
| ManagedObjectType mockFaultLogEntry{{ |
| std::make_pair( |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{{ |
| // First Mock Completed Status |
| std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Status", |
| "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" |
| ) |
| }} |
| ), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Type", |
| "xyz.openbmc_project.Common.FaultLogType.FaultLogTypes.CPER" |
| ), |
| std::make_pair( |
| "PrimaryLogId", |
| "1" |
| ) |
| }} |
| ) |
| }} |
| ) |
| }}; |
| return managedStore::MockManagedStoreTest::CreateValueType(std::move(mockFaultLogEntry)); |
| } |
| |
| |
| TEST_F(SnapshotFixture, LogServiceFaultLogEntriesGetSuccessfulResponse){ |
| std::string systemId = "system1"; |
| |
| // Looking for Key: kManagedObject|xyz.openbmc_project.Dump.Manager|/xyz/openbmc_project/dump |
| KeyType key(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key, CreateMockFaultLogEntry()).ok()); |
| |
| handleLogServiceFaultLogEntriesGet( |
| app_, CreateRequest(), share_async_resp_, systemId); |
| |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json["@odata.id"], |
| "/redfish/v1/Systems/" + systemId + "/LogServices/FaultLog/Entries"); |
| EXPECT_EQ(json["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(json["Description"], "Collection of FaultLog Dump Entries"); |
| EXPECT_EQ(json["Name"], "FaultLog Dump Entries"); |
| EXPECT_EQ(json["Members"].size(), json["Members@odata.count"]); |
| |
| // Hardcoding the verification of the Members check |
| nlohmann::json& faultLog1 = json["Members"][0]; |
| EXPECT_EQ(faultLog1["@odata.id"], "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(faultLog1["@odata.type"], "#LogEntry.v1_11_0.LogEntry"); |
| EXPECT_EQ(faultLog1["AdditionalDataURI"], "/redfish/v1/Systems/system1/LogServices/HostCper/Entries/1"); |
| EXPECT_EQ(faultLog1["Created"], "1970-01-01T00:00:00.000000+00:00"); |
| EXPECT_EQ(faultLog1["DiagnosticDataType"], "OEM"); |
| EXPECT_EQ(faultLog1["EntryType"], "Oem"); |
| EXPECT_EQ(faultLog1["Id"], "1"); |
| EXPECT_EQ(faultLog1["Links"]["RelatedLogEntries"].size(), 1); |
| EXPECT_EQ(faultLog1["Links"]["RelatedLogEntries"][0]["@odata.id"], "/redfish/v1/Systems/system1/LogServices/HostCper/Entries/1"); |
| EXPECT_EQ(faultLog1["Name"], "FaultLog Dump Entry"); |
| EXPECT_EQ(faultLog1["OEMDiagnosticDataType"], "OpenBMC Fault Log"); |
| EXPECT_EQ(faultLog1["OemRecordFormat"], "CPER"); |
| |
| // Response validation |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| nlohmann::json createLogEntry(const std::string& systemId, const std::string& entryId, |
| const std::string& hostCperEntryUri){ |
| nlohmann::json entry; |
| entry["@odata.id"] = "/redfish/v1/Systems/" + systemId + "/LogServices/FaultLog/Entries/" + entryId; |
| entry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; |
| entry["AdditionalDataURI"] = hostCperEntryUri; |
| entry["Created"] = "2024-08-26T20:21:09.735414+00:00"; |
| entry["DiagnosticDataType"] = "OEM"; |
| entry["EntryType"] = "Oem"; |
| entry["Id"] = entryId; |
| |
| nlohmann::json hostCperEntry; |
| hostCperEntry["@odata.id"] = hostCperEntryUri; |
| entry["Links"]["RelatedLogEntries"][0] = hostCperEntry; |
| return entry; |
| } |
| |
| TEST_F(SnapshotFixture, QueryFaultCollectionFilterIncomplete){ |
| std::string systemId = "system1"; |
| const std::string collectionUri = |
| "/redfish/v1/Systems/" + systemId + "/LogServices/HostCper/Entries"; |
| const std::string hostCperEntryUri = collectionUri + "/1"; |
| |
| std::string_view fileContent = "Q1BFUgEB/////wEAAgAAA"; |
| BMCWEB_ROUTE( |
| app_, |
| "/redfish/v1/Systems/<str>/LogServices/HostCper/Entries") |
| .privileges(redfish::privileges::getLogServiceCollection) |
| .methods(boost::beast::http::verb::get)( |
| [this, &fileContent](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string systemId) { |
| if (!redfish::setUpRedfishRoute(app_, req, asyncResp)) |
| { |
| return; |
| } |
| nlohmann::json& thisEntry = asyncResp->res.jsonValue; |
| thisEntry["@odata.id"] = "/redfish/v1/Systems/" + systemId + "/LogServices/HostCper/Entries"; |
| thisEntry["@odata.type"] = "#LogEntryCollection.LogEntryCollection"; |
| thisEntry["Description"] = "Collection of Host CPER Entries"; |
| thisEntry["Members"] = nlohmann::json::array(); |
| thisEntry["Members@odata.count"] = 1; |
| thisEntry["Name"] = "Host CPER Entries"; |
| |
| nlohmann::json hostCperEntry; |
| hostCperEntry["@odata.id"] = "/redfish/v1/Systems/" + systemId + |
| "/LogServices/HostCper/Entries/1"; |
| hostCperEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; |
| hostCperEntry["Created"] = "2024-08-26T20:21:09.735414+00:00"; |
| hostCperEntry["DiagnosticData"] = fileContent; |
| hostCperEntry["DiagnosticDataType"] = "CPER"; |
| hostCperEntry["EntryType"] = "Oem"; |
| hostCperEntry["Id"] = "1"; |
| hostCperEntry["Name"] = "Host CPER Entry"; |
| thisEntry["Members"].push_back(std::move(hostCperEntry)); |
| }); |
| |
| app_.validate(); |
| app_.run(); |
| |
| nlohmann::json originalMembers = nlohmann::json::array(); |
| |
| std::unordered_map<std::string, |
| nlohmann::json::json_pointer> faultLogEntries; |
| |
| nlohmann::json::json_pointer path1 = |
| ""_json_pointer /0/"Links"/"RelatedLogEntries"/0; |
| faultLogEntries.emplace(hostCperEntryUri, path1); |
| originalMembers.push_back(createLogEntry(systemId, "1", hostCperEntryUri)); |
| nlohmann::json::json_pointer path2 = |
| ""_json_pointer /1/"Links"/"RelatedLogEntries"/1; |
| faultLogEntries.emplace(hostCperEntryUri, path2); |
| originalMembers.push_back(createLogEntry(systemId, "2", hostCperEntryUri)); |
| |
| redfish::queryFaultCollection( |
| app_, |
| CreateRequest(), |
| share_async_resp_, |
| collectionUri, |
| faultLogEntries, |
| originalMembers); |
| |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members"].size(), 1); |
| EXPECT_EQ( |
| share_async_resp_->res.jsonValue["Members"][path1 / "DiagnosticData"], |
| fileContent); |
| } |
| |
| void commonChecksForBootLogService( |
| const std::shared_ptr<bmcweb::AsyncResp>& share_async_resp, |
| const std::string& serviceODataId) |
| { |
| nlohmann::json& json = share_async_resp->res.jsonValue; |
| EXPECT_EQ(json["@odata.type"], "#LogService.v1_1_0.LogService"); |
| EXPECT_EQ(json["Name"], "Boot Time Log Service"); |
| EXPECT_EQ(json["Description"], "Boot Time Log Service"); |
| EXPECT_EQ(json["Id"], "BootTime"); |
| EXPECT_EQ(json["OverWritePolicy"], "WrapsWhenFull"); |
| EXPECT_EQ(json["@odata.id"], serviceODataId); |
| EXPECT_EQ(json["LogEntryType"], "Multiple"); |
| EXPECT_TRUE(json.contains("Entries")); |
| EXPECT_EQ(json["Entries"]["@odata.id"], serviceODataId + "/Entries"); |
| // Response validation |
| EXPECT_EQ(share_async_resp->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, GetSystemBootLogServicesMultihost) |
| { |
| std::string systemId = "system1"; |
| |
| handleSystemBootTimeLogServiceGet(app_, CreateRequest(), share_async_resp_, |
| systemId); |
| |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| TEST_F(SnapshotFixture, GetSystemBootLogServices) |
| { |
| std::string systemId = "system"; |
| |
| handleSystemBootTimeLogServiceGet(app_, CreateRequest(), share_async_resp_, |
| systemId); |
| |
| RunIoUntilDone(); |
| |
| std::string serviceODataId = |
| "/redfish/v1/Systems/" + systemId + "/LogServices/BootTime"; |
| commonChecksForBootLogService(share_async_resp_, serviceODataId); |
| } |
| |
| TEST_F(SnapshotFixture, GetManagerLogServices) |
| { |
| handleManagerBootTimeLogServiceGet(app_, CreateRequest(), |
| share_async_resp_); |
| |
| RunIoUntilDone(); |
| |
| std::string serviceODataId = |
| "/redfish/v1/Managers/bmc/LogServices/BootTime"; |
| commonChecksForBootLogService(share_async_resp_, serviceODataId); |
| } |
| |
| TEST_F(SnapshotFixture, GetSystemBootLogServiceEntriesMultihost) |
| { |
| std::string systemId = "system1"; |
| |
| handleSystemBootTimeLogsEntryCollectionGet(app_, CreateRequest(), |
| share_async_resp_, systemId); |
| |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| void setCheckpointsInBootLogService( |
| const std::string& host, const std::vector<BootTimeCheckpoint> checkpoints, |
| bool dbusException) |
| { |
| if (dbusException) |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const std::vector<BootTimeCheckpoint>&)>&&>(), |
| "com.google.gbmc.boot_time_monitor", |
| "/xyz/openbmc_project/time/boot/" + host, |
| "xyz.openbmc_project.Time.Boot.Checkpoint", |
| "GetCheckpointList")) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| } |
| else |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const std::vector<BootTimeCheckpoint>&)>&&>(), |
| "com.google.gbmc.boot_time_monitor", |
| "/xyz/openbmc_project/time/boot/" + host, |
| "xyz.openbmc_project.Time.Boot.Checkpoint", |
| "GetCheckpointList")) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< |
| std::vector<BootTimeCheckpoint>>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<std::vector<BootTimeCheckpoint>>( |
| checkpoints))); |
| } |
| } |
| |
| void setDurationsInBootLogService( |
| const std::string& host, const std::vector<BootTimeDuration>& durations, |
| bool dbusException) |
| { |
| if (dbusException) |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const std::vector<BootTimeDuration>&)>&&>(), |
| "com.google.gbmc.boot_time_monitor", |
| "/xyz/openbmc_project/time/boot/" + host, |
| "xyz.openbmc_project.Time.Boot.Duration", |
| "GetAdditionalDurations")) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| } |
| else |
| { |
| |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const std::vector<BootTimeDuration>&)>&&>(), |
| "com.google.gbmc.boot_time_monitor", |
| "/xyz/openbmc_project/time/boot/" + host, |
| "xyz.openbmc_project.Time.Boot.Duration", |
| "GetAdditionalDurations")) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< |
| std::vector<BootTimeDuration>>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<std::vector<BootTimeDuration>>( |
| durations))); |
| } |
| } |
| |
| void setIsRebootingInBootLogService(const std::string& host, |
| const bool& isRebooting, bool dbusException) |
| { |
| if (!dbusException) |
| { |
| KeyType key(ManagedType::kManagedProperty, |
| "com.google.gbmc.boot_time_monitor", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/time/boot/" + host), |
| "xyz.openbmc_project.Time.Boot.Statistic", "IsRebooting"); |
| std::shared_ptr<ValueType> mockIsRebooting = |
| managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(isRebooting)); |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key, mockIsRebooting) |
| .ok()); |
| } |
| else |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&)>&&>(), |
| "com.google.gbmc.boot_time_monitor", |
| "/xyz/openbmc_project/time/boot/" + host, |
| "org.freedesktop.DBus.Properties", "Get", |
| "xyz.openbmc_project.Time.Boot.Statistic", |
| "IsRebooting", dbus::utility::DbusVariantType(true))) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateFailedAsyncPostDbusCallThreadSafeAction:: |
| SimulateFailedAsyncPostDbusCall()); |
| } |
| } |
| |
| void validateBootTimeCheckpoint( |
| const nlohmann::json& diagnosticData, const nlohmann::json& logEntry, |
| const std::optional<size_t>& specificIndex, |
| const std::string& parentODataId, |
| const std::vector<BootTimeCheckpoint>& checkpoints) |
| { |
| bool found = false; |
| EXPECT_EQ(diagnosticData.size(), 3); |
| EXPECT_TRUE(diagnosticData.contains("Name")); |
| EXPECT_TRUE(diagnosticData.contains("WallTimeMs")); |
| EXPECT_TRUE(diagnosticData.contains("MonoTimeMs")); |
| size_t currentIndex = specificIndex.value_or(0); |
| for (auto checkpoint : checkpoints) |
| { |
| const auto [name, wallTime, monoTime] = checkpoint; |
| if (diagnosticData["Name"] == name && |
| diagnosticData["WallTimeMs"] == wallTime && |
| diagnosticData["MonoTimeMs"] == monoTime) |
| { |
| found = true; |
| const std::string id = "Checkpoint" + std::to_string(currentIndex); |
| EXPECT_EQ(logEntry.at("Id").get<std::string>(), id); |
| EXPECT_EQ(logEntry.at("@odata.id").get<std::string>(), |
| parentODataId + "/" + id); |
| break; |
| } |
| currentIndex++; |
| } |
| EXPECT_TRUE(found); |
| } |
| |
| void validateBootTimeDuration(const nlohmann::json& diagnosticData, |
| const nlohmann::json& logEntry, |
| const std::optional<size_t>& specificIndex, |
| const std::string& parentODataId, |
| const std::vector<BootTimeDuration>& durations) |
| { |
| bool found = false; |
| EXPECT_EQ(diagnosticData.size(), 2); |
| EXPECT_TRUE(diagnosticData.contains("Name")); |
| EXPECT_TRUE(diagnosticData.contains("DurationMs")); |
| size_t currentIndex = specificIndex.value_or(0); |
| for (auto duration : durations) |
| { |
| const auto [name, durationMs] = duration; |
| if (diagnosticData["Name"] == name && |
| diagnosticData["DurationMs"] == durationMs) |
| { |
| found = true; |
| const std::string id = "Duration" + std::to_string(currentIndex); |
| EXPECT_EQ(logEntry.at("Id").get<std::string>(), id); |
| EXPECT_EQ(logEntry.at("@odata.id").get<std::string>(), |
| parentODataId + "/" + id); |
| break; |
| } |
| currentIndex++; |
| } |
| EXPECT_TRUE(found); |
| } |
| |
| void validateBootTimeStatistic(const nlohmann::json& diagnosticData, |
| const nlohmann::json& logEntry, |
| const std::string& parentODataId, |
| const bool& isRebooting) |
| { |
| EXPECT_EQ(diagnosticData.size(), 1); |
| EXPECT_TRUE(diagnosticData.contains("IsRebooting")); |
| EXPECT_EQ(diagnosticData["IsRebooting"], isRebooting); |
| const std::string id = "Statistic0"; |
| EXPECT_EQ(logEntry.at("Id").get<std::string>(), id); |
| EXPECT_EQ(logEntry.at("@odata.id").get<std::string>(), |
| parentODataId + "/" + id); |
| } |
| |
| void checkLogEntries(const nlohmann::json& logEntries, |
| const std::vector<BootTimeCheckpoint>& checkpoints, |
| const std::vector<BootTimeDuration>& durations, |
| const std::optional<bool> isRebooting, |
| const std::string& parentODataId, |
| const std::optional<size_t> specificIndex) |
| { |
| for (const nlohmann::json& logEntry : logEntries) |
| { |
| EXPECT_EQ(logEntry["@odata.type"], "#LogEntry.v1_15_0.LogEntry"); |
| EXPECT_EQ(logEntry["Name"], "Boot Time Log Entry"); |
| EXPECT_EQ(logEntry["EntryType"], "Oem"); |
| EXPECT_TRUE(logEntry.contains("OEMDiagnosticDataType")); |
| EXPECT_TRUE(logEntry.contains("DiagnosticData")); |
| |
| std::string encodedData = logEntry["DiagnosticData"]; |
| EXPECT_TRUE(encodedData.size() > 0); |
| nlohmann::json diagnosticData; |
| std::string diagnosticDataStr; |
| EXPECT_TRUE(crow::utility::base64Decode(encodedData, diagnosticDataStr)) |
| << "Decoding failed for the DiagnosticData"; |
| |
| EXPECT_EQ(logEntry["Message"], diagnosticDataStr); |
| try |
| { |
| diagnosticData = nlohmann::json::parse(diagnosticDataStr); |
| } |
| catch (nlohmann::json::parse_error& e) |
| { |
| ADD_FAILURE() << "Could not parse diagnostic data. " << e.what(); |
| } |
| |
| std::string type = logEntry["OEMDiagnosticDataType"]; |
| if (type == "Checkpoint") |
| { |
| validateBootTimeCheckpoint(diagnosticData, logEntry, specificIndex, |
| parentODataId, checkpoints); |
| } |
| else if (type == "Duration") |
| { |
| validateBootTimeDuration(diagnosticData, logEntry, specificIndex, |
| parentODataId, durations); |
| } |
| else if (type == "Statistic") |
| { |
| validateBootTimeStatistic(diagnosticData, logEntry, parentODataId, |
| isRebooting.value_or(false)); |
| } |
| else |
| { |
| ADD_FAILURE() << "Unexpected OEMDiagnosticDataType found: " << type; |
| } |
| } |
| } |
| |
| TEST_F(SnapshotFixture, GetSystemBootLogServiceEntries) |
| { |
| std::string systemId = "system"; |
| |
| std::vector<BootTimeCheckpoint> checkpoints; |
| checkpoints.push_back(BootTimeCheckpoint({"dummyState", 100, 200})); |
| setCheckpointsInBootLogService("host0", checkpoints, false); |
| |
| std::vector<BootTimeDuration> durations; |
| durations.push_back(BootTimeDuration({"dummyDuration", 300})); |
| setDurationsInBootLogService("host0", durations, false); |
| |
| setIsRebootingInBootLogService("host0", true, false); |
| |
| // call target method |
| handleSystemBootTimeLogsEntryCollectionGet(app_, CreateRequest(), |
| share_async_resp_, systemId); |
| // Perform dbus calls |
| RunIoUntilDone(); |
| |
| const std::string odataId = |
| "/redfish/v1/Systems/" + systemId + "/LogServices/BootTime/Entries"; |
| // expect starts |
| EXPECT_EQ(share_async_resp_->res.jsonValue["@odata.id"], odataId); |
| |
| checkLogEntries(share_async_resp_->res.jsonValue["Members"], checkpoints, |
| durations, true, odataId, std::nullopt); |
| size_t expected_entries = checkpoints.size() + durations.size() + 1; |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members@odata.count"], |
| expected_entries); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, GetManagerBootLogServiceEntries) |
| { |
| std::vector<BootTimeCheckpoint> checkpoints; |
| checkpoints.push_back(BootTimeCheckpoint({"dummyState", 100, 200})); |
| setCheckpointsInBootLogService("bmc", checkpoints, false); |
| |
| std::vector<BootTimeDuration> durations; |
| durations.push_back(BootTimeDuration({"dummyDuration", 300})); |
| setDurationsInBootLogService("bmc", durations, false); |
| |
| setIsRebootingInBootLogService("bmc", true, false); |
| |
| // call target method |
| handleManagerBootTimeLogsEntryCollectionGet(app_, CreateRequest(), |
| share_async_resp_); |
| // Perform dbus calls |
| RunIoUntilDone(); |
| |
| // expect starts |
| const std::string odataId = |
| "/redfish/v1/Managers/bmc/LogServices/BootTime/Entries"; |
| EXPECT_EQ(share_async_resp_->res.jsonValue["@odata.id"], odataId); |
| |
| checkLogEntries(share_async_resp_->res.jsonValue["Members"], checkpoints, |
| durations, true, odataId, std::nullopt); |
| size_t expected_entries = checkpoints.size() + durations.size() + 1; |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members@odata.count"], |
| expected_entries); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| struct BootLogEntryTestCase |
| { |
| BootTimeDataType type; |
| std::vector<BootTimeCheckpoint> checkpoints; |
| std::vector<BootTimeDuration> durations; |
| std::optional<bool> rebooting; |
| std::string entryId; |
| bool dbusException; |
| size_t expectedIndex; |
| bool expectErr; |
| }; |
| |
| void testBootLogEntry(App& app, const crow::Request& req, |
| std::shared_ptr<bmcweb::AsyncResp>& share_async_resp, |
| const std::string& systemId, const std::string& host, |
| const std::string odataId, const bool& testSystem, |
| const std::function<void()>& RunIoUntilDone) |
| { |
| std::vector<BootTimeCheckpoint> defaultCheckpoints; |
| defaultCheckpoints.push_back(BootTimeCheckpoint({"dummyState1", 100, 200})); |
| defaultCheckpoints.push_back(BootTimeCheckpoint({"dummyState2", 300, 400})); |
| std::vector<BootTimeDuration> defaultDurations; |
| defaultDurations.push_back(BootTimeDuration({"dummyDuration1", 300})); |
| defaultDurations.push_back(BootTimeDuration({"dummyDuration2", 600})); |
| |
| std::vector<BootLogEntryTestCase> testCases = { |
| // successful response |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "Checkpoint0", |
| false, |
| 0, |
| false}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "Checkpoint1", |
| false, |
| 1, |
| false}, |
| {BootTimeDataType::DURATION, |
| {}, |
| defaultDurations, |
| std::nullopt, |
| "Duration0", |
| false, |
| 0, |
| false}, |
| {BootTimeDataType::DURATION, |
| {}, |
| defaultDurations, |
| std::nullopt, |
| "Duration1", |
| false, |
| 1, |
| false}, |
| {BootTimeDataType::STATISTIC, |
| {}, |
| {}, |
| true, |
| "Statistic0", |
| false, |
| 0, |
| false}, // 5 |
| // error response |
| {BootTimeDataType::CHECKPOINT, |
| {}, |
| {}, |
| std::nullopt, |
| "Checkpoint0", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "Checkpoint2", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::DURATION, |
| {}, |
| {}, |
| std::nullopt, |
| "Duration0", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::DURATION, |
| {}, |
| defaultDurations, |
| std::nullopt, |
| "Duration2", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::STATISTIC, |
| {}, |
| {}, |
| true, |
| "Statistic1", |
| false, |
| 0, |
| true}, // 10 |
| {BootTimeDataType::STATISTIC, |
| {}, |
| {}, |
| std::nullopt, |
| "Statistic0", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "abc", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "-", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "Checkpoint", |
| false, |
| 0, |
| true}, // 15 |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "Checkpoint-1", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "-1", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "CheckpointABC", |
| false, |
| 0, |
| true}, |
| {BootTimeDataType::CHECKPOINT, |
| defaultCheckpoints, |
| {}, |
| std::nullopt, |
| "Checkpoint0", |
| true, |
| 0, |
| true}, |
| {BootTimeDataType::DURATION, |
| {}, |
| defaultDurations, |
| std::nullopt, |
| "Duration0", |
| true, |
| 0, |
| true}, // 20 |
| {BootTimeDataType::STATISTIC, |
| {}, |
| {}, |
| true, |
| "Statistic0", |
| true, |
| 0, |
| true}, // 21 |
| }; |
| |
| size_t testNo = 1; |
| for (auto testCase : testCases) |
| { |
| std::cout << "Test Case#" << testNo++ << '\n'; |
| // Setup |
| if (testCase.type == BootTimeDataType::CHECKPOINT) |
| { |
| setCheckpointsInBootLogService(host, testCase.checkpoints, |
| testCase.dbusException); |
| } |
| else if (testCase.type == BootTimeDataType::DURATION) |
| { |
| setDurationsInBootLogService(host, testCase.durations, |
| testCase.dbusException); |
| } |
| else if (testCase.rebooting.has_value()) |
| { |
| setIsRebootingInBootLogService(host, testCase.rebooting.value(), |
| testCase.dbusException); |
| } |
| // Call Target Method |
| if (testSystem) |
| { |
| handleSystemBootTimeLogsEntryGet(app, req, share_async_resp, |
| systemId, testCase.entryId); |
| } |
| else |
| { |
| handleManagerBootTimeLogsEntryGet(app, req, share_async_resp, |
| testCase.entryId); |
| } |
| // Perform dbus calls |
| RunIoUntilDone(); |
| // Match expectations |
| if (testCase.expectErr) |
| { |
| EXPECT_TRUE(share_async_resp->res.jsonValue.contains("error")); |
| continue; |
| } |
| else |
| { |
| EXPECT_EQ(share_async_resp->res.result(), |
| boost::beast::http::status::ok); |
| } |
| nlohmann::json logEntryArray = nlohmann::json::array(); |
| logEntryArray.push_back(share_async_resp->res.jsonValue); |
| if (testCase.type == BootTimeDataType::CHECKPOINT) |
| { |
| checkLogEntries(logEntryArray, |
| {testCase.checkpoints[testCase.expectedIndex]}, {}, |
| std::nullopt, odataId, testCase.expectedIndex); |
| } |
| else if (testCase.type == BootTimeDataType::DURATION) |
| { |
| checkLogEntries(logEntryArray, {}, |
| {testCase.durations[testCase.expectedIndex]}, |
| std::nullopt, odataId, testCase.expectedIndex); |
| } |
| else |
| { |
| checkLogEntries(logEntryArray, {}, {}, testCase.rebooting, odataId, |
| 0); |
| } |
| } |
| } |
| |
| TEST_F(SnapshotFixture, GetSystemBootLogEntry) |
| { |
| const std::string odataId = |
| "/redfish/v1/Systems/system/LogServices/BootTime/Entries"; |
| testBootLogEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "host0", odataId, true, RunIoUntilDone); |
| } |
| |
| TEST_F(SnapshotFixture, GetManagerBootLogEntry) |
| { |
| const std::string odataId = |
| "/redfish/v1/Managers/bmc/LogServices/BootTime/Entries"; |
| testBootLogEntry(app_, CreateRequest(), share_async_resp_, "", "bmc", |
| odataId, false, RunIoUntilDone); |
| } |
| |
| #ifdef BMCWEB_ENABLE_RASMANAGER_EVENT_LOG |
| const std::string RasManagerLogName = |
| "/com/intel/ras/logs/Correctable_1_1728369268114"; |
| |
| std::shared_ptr<ValueType> CreateMockRasManagerEntry(){ |
| MapperGetSubTreePathsResponse mockRasManagerEntry{{RasManagerLogName}}; |
| return managedStore::MockManagedStoreTest::CreateValueType(std::move(mockRasManagerEntry)); |
| } |
| |
| std::shared_ptr<ValueType> CreateMockRasManagerLogEntry() |
| { |
| DBusPropertiesMap mockRasManagerLogEntry{ |
| {std::make_pair("TimestampMs", 1728369268114ULL)}}; |
| return managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockRasManagerLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, LogServiceRasManagerEntriesGetSuccessfulResponse){ |
| std::string systemId = "system"; |
| |
| // kManagedSubtreePaths|/com/intel/ras/logs|0|xyz.openbmc_project.Time.EpochTime |
| KeyType key(ManagedType::kManagedSubtreePaths, "/com/intel/ras/logs", 0, |
| {"xyz.openbmc_project.Time.EpochTime"}); |
| |
| // insert for handleLogServicesRasManagerEntriesCollectionGet |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key, CreateMockRasManagerEntry()).ok()); |
| |
| // kManagedPropertyMap|com.intel.RAS|/com/intel/ras/logs/Correctable_1_1728369268114|xyz.openbmc_project.Time.EpochTime |
| KeyType key2(ManagedType::kManagedPropertyMap, "com.intel.RAS", |
| RasManagerLogName, "xyz.openbmc_project.Time.EpochTime"); |
| |
| // insert for logRasManagerEntry |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore( |
| key2, CreateMockRasManagerLogEntry()) |
| .ok()); |
| |
| std::string filePath = "/tmp/ras-manager/output/Correctable_1_1728369268114.cpr"; |
| std::filesystem::path dirPath = std::filesystem::path(filePath).parent_path(); |
| std::filesystem::create_directories(dirPath); |
| std::ofstream file(filePath); |
| file << "CPER" << '\n'; |
| file.close(); |
| |
| handleLogServicesRasManagerEntriesCollectionGet( |
| app_, CreateRequest(), share_async_resp_, systemId); |
| |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json["@odata.id"], |
| "/redfish/v1/Systems/" + systemId + "/LogServices/HostCper/Entries"); |
| EXPECT_EQ(json["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(json["Description"], "Collection of RasManager Entries"); |
| EXPECT_EQ(json["Name"], "Open BMC RasManager Entries"); |
| EXPECT_EQ(json["Members"].size(), json["Members@odata.count"]); |
| |
| // Hardcoding the verification of the Members check |
| nlohmann::json& rasLog1 = json["Members"][0]; |
| EXPECT_EQ(rasLog1["@odata.id"], "/redfish/v1/Systems/" + systemId + "/LogServices/HostCper/Entries/Correctable_1_1728369268114"); |
| EXPECT_EQ(rasLog1["@odata.type"], "#LogEntry.v1_9_0.LogEntry"); |
| EXPECT_EQ(rasLog1["Created"], "2024-10-08T06:34:28.114+00:00"); |
| EXPECT_EQ(rasLog1["DiagnosticData"], "Q1BFUgo="); |
| EXPECT_EQ(rasLog1["DiagnosticDataType"], "CPER"); |
| EXPECT_EQ(rasLog1["EntryType"], "Oem"); |
| EXPECT_EQ(rasLog1["Id"], "Correctable_1_1728369268114"); |
| EXPECT_EQ(rasLog1["Name"], "RasManager"); |
| EXPECT_EQ(rasLog1["OemRecordFormat"], "CPER"); |
| |
| // Response validation |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| #endif // BMCWEB_ENABLE_RASMANAGER_EVENT_LOG |
| |
| #ifdef BMCWEB_ENABLE_PPR |
| TEST_F(SnapshotFixture, LogServicehandlePPRServiceGet) |
| { |
| handlePPRServiceGet(app_, CreateRequest(), share_async_resp_); |
| |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/PostPackageRepair"); |
| EXPECT_EQ(json["Members"].size(), json["Members@odata.count"]); |
| EXPECT_GT(json["Members@odata.count"], 0); |
| EXPECT_GT(json["Actions"], 0); |
| } |
| |
| constexpr char const* pprFileInterface = |
| "xyz.openbmc_project.PostPackageRepair.PprData"; |
| constexpr char const* pprFileObject = "xyz.openbmc_project.PostPackageRepair"; |
| constexpr char const* pprFilePath = "/xyz/openbmc_project/PostPackageRepair"; |
| |
| constexpr uint16_t pprStatusRepairEntryNum = 1; |
| constexpr uint16_t pprStatusRepairType = 2; |
| constexpr uint16_t pprStatusSocNum = 3; |
| constexpr uint16_t pprStatusRepairResult = 4; |
| std::vector<uint16_t> pprStatusPayload = {5, 6}; |
| constexpr char const* pprFileRequestJson = |
| "{\"RepairType\":2, \"RepairEntryNum\":1, \"SocNum\":3, \"Payload\":[5, 6]}"; |
| constexpr char const* pprConfigRequestJson = |
| "{\"autoScheduleBtAsHard\":true, \"autoScheduleRtAsBtPpr\":false}"; |
| |
| void setPPRStatus(bool dbusException) |
| { |
| const PostPackageRepairStatusParam pprParam{ |
| {{ |
| pprStatusRepairEntryNum, |
| pprStatusRepairType, |
| pprStatusSocNum, |
| pprStatusRepairResult, |
| pprStatusPayload, |
| }}, |
| }; |
| if (dbusException) |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const PostPackageRepairStatusParam&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "getPostPackageRepairStatus")) |
| .Times(1) |
| .WillOnce( |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| } |
| else |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const PostPackageRepairStatusParam&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "getPostPackageRepairStatus")) |
| .Times(1) |
| .WillOnce( |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< |
| PostPackageRepairStatusParam>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<PostPackageRepairStatusParam>( |
| pprParam))); |
| } |
| } |
| |
| TEST_F(SnapshotFixture, FailedGetPostPackageRepairStatus) |
| { |
| setPPRStatus(true); |
| |
| getPostPackageRepairStatus(share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullyGetPostPackageRepairStatus) |
| { |
| setPPRStatus(false); |
| |
| getPostPackageRepairStatus(share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, FailedhandlePPRStatusGet) |
| { |
| setPPRStatus(true); |
| |
| handlePPRStatusGet(app_, CreateRequest(), share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullyhandlePPRStatusGet) |
| { |
| setPPRStatus(false); |
| |
| handlePPRStatusGet(app_, CreateRequest(), share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_GT(json["Members@odata.count"], 0); |
| EXPECT_TRUE(json["Members"][0].contains("repairEntryNum")); |
| EXPECT_EQ(json["Members"][0]["repairEntryNum"], pprStatusRepairEntryNum); |
| EXPECT_TRUE(json["Members"][0].contains("repairType")); |
| EXPECT_EQ(json["Members"][0]["repairType"], pprStatusRepairType); |
| EXPECT_TRUE(json["Members"][0].contains("socNum")); |
| EXPECT_EQ(json["Members"][0]["socNum"], pprStatusSocNum); |
| EXPECT_TRUE(json["Members"][0].contains("repairResult")); |
| EXPECT_EQ(json["Members"][0]["repairResult"], pprStatusRepairResult); |
| EXPECT_TRUE(json["Members"][0].contains("payload")); |
| EXPECT_EQ(json["Members"][0]["payload"], pprStatusPayload); |
| } |
| |
| void prepareSetPostPackageRepairDataExpectCall( |
| int dbusException /*0 for no error*/) |
| { |
| const bool recordAdd = true; |
| const uint32_t startRuntimeRepair = 2; |
| if (dbusException >= 3) |
| { |
| EXPECT_CALL( |
| *managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const bool&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "setPostPackageRepairData", pprStatusRepairEntryNum, |
| pprStatusRepairType, pprStatusSocNum, pprStatusPayload)) |
| .Times(testing::AtMost(1)) |
| .WillOnce( |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| return; |
| } |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const bool&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "setPostPackageRepairData", pprStatusRepairEntryNum, |
| pprStatusRepairType, pprStatusSocNum, pprStatusPayload)) |
| .Times(1) |
| .WillOnce( |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction<bool>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<bool>(recordAdd))); |
| if (dbusException >= 2) |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| setProperty(pprFileObject, pprFilePath, pprFileInterface, |
| "RecordAdd", |
| dbus::utility::DbusVariantType{true}, _)) |
| .Times(1) |
| .WillOnce(SimulateFailedAsyncSetPropertyDbusCallAction:: |
| SimulateFailedAsyncSetPropertyDbusCall()); |
| return; |
| } |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| setProperty(pprFileObject, pprFilePath, pprFileInterface, |
| "RecordAdd", dbus::utility::DbusVariantType{true}, |
| _)) |
| .Times(1) |
| .WillOnce(SimulateSuccessfulAsyncSetPropertyDbusCallAction:: |
| SimulateSuccessfulAsyncSetPropertyDbusCall()); |
| if (dbusException >= 1) |
| { |
| EXPECT_CALL( |
| *managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const uint32_t&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "startRuntimeRepair", 0)) |
| .Times(testing::AtMost(1)) |
| .WillOnce( |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| return; |
| } |
| |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const uint32_t&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "startRuntimeRepair", 0)) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< |
| uint32_t>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<uint32_t>(startRuntimeRepair))); |
| } |
| |
| TEST_F(SnapshotFixture, FailedSetPostPackageRepairData) |
| { |
| prepareSetPostPackageRepairDataExpectCall(3); |
| |
| setPostPackageRepairData(share_async_resp_, 0 /*Index*/, |
| pprStatusRepairEntryNum, pprStatusRepairType, |
| pprStatusSocNum, pprStatusPayload); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, setPostPackageRepairDataFailedSetProperty) |
| { |
| prepareSetPostPackageRepairDataExpectCall(2); |
| |
| setPostPackageRepairData(share_async_resp_, 0 /*Index*/, |
| pprStatusRepairEntryNum, pprStatusRepairType, |
| pprStatusSocNum, pprStatusPayload); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, setPostPackageRepairDataFailedStartRuntimeRepair) |
| { |
| prepareSetPostPackageRepairDataExpectCall(1); |
| |
| setPostPackageRepairData(share_async_resp_, 0 /*Index*/, |
| pprStatusRepairEntryNum, pprStatusRepairType, |
| pprStatusSocNum, pprStatusPayload); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullySetPostPackageRepairData) |
| { |
| prepareSetPostPackageRepairDataExpectCall(0); |
| |
| setPostPackageRepairData(share_async_resp_, 0 /*Index*/, |
| pprStatusRepairEntryNum, pprStatusRepairType, |
| pprStatusSocNum, pprStatusPayload); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, FailedOobPprEnableHandlePPRFilePatch) |
| { |
| // fail because oobPprEnable == false |
| KeyType key(ManagedType::kManagedProperty, pprFileObject, |
| sdbusplus::message::object_path(pprFilePath), pprFileInterface, |
| "oobPprEnable"); |
| std::shared_ptr<ValueType> oobPprEnable = |
| CreateValueType(DbusVariantType(false)); |
| |
| EXPECT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key, oobPprEnable) |
| .ok()); |
| |
| handlePPRFilePatch(app_, CreateRequest(pprFileRequestJson), |
| share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullyHandlePPRFilePatch) |
| { |
| KeyType key(ManagedType::kManagedProperty, pprFileObject, |
| sdbusplus::message::object_path(pprFilePath), pprFileInterface, |
| "oobPprEnable"); |
| std::shared_ptr<ValueType> oobPprEnable = |
| CreateValueType(DbusVariantType(true)); |
| |
| EXPECT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key, oobPprEnable) |
| .ok()); |
| |
| prepareSetPostPackageRepairDataExpectCall(0); |
| |
| handlePPRFilePatch(app_, CreateRequest(pprFileRequestJson), |
| share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, FailedGetPostPackageRepairConfig) |
| { |
| EXPECT_CALL( |
| *managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const std::vector<uint16_t>&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "getPostPackageRepairConfig")) |
| .Times(testing::AtMost(1)) |
| .WillOnce( |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| |
| getPostPackageRepairConfig(share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullyGetPostPackageRepairConfig) |
| { |
| const uint16_t oobPprEnable = 1; // true |
| const uint16_t RtToBt = 0; // false |
| const uint16_t BtSetToHard = 0; // false |
| const std::vector<uint16_t> config{{oobPprEnable, RtToBt, BtSetToHard}}; |
| |
| EXPECT_CALL( |
| *managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const std::vector<uint16_t>&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "getPostPackageRepairConfig")) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< |
| std::vector<uint16_t>>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<std::vector<uint16_t>>(config))); |
| |
| getPostPackageRepairConfig(share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_GT(json["Members@odata.count"], 0); |
| EXPECT_TRUE(json["Members"][0].contains("OobPprEnable")); |
| EXPECT_TRUE(json["Members"][0].contains("autoScheduleRtAsBtPpr")); |
| EXPECT_TRUE(json["Members"][0].contains("autoScheduleBtAsHard")); |
| EXPECT_EQ(json["Members"][0]["OobPprEnable"], true); |
| EXPECT_EQ(json["Members"][0]["autoScheduleRtAsBtPpr"], false); |
| EXPECT_EQ(json["Members"][0]["autoScheduleBtAsHard"], false); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullyhandlePPRConfigGet) |
| { |
| const uint16_t oobPprEnable = 1; // true |
| const uint16_t RtToBt = 0; // false |
| const uint16_t BtSetToHard = 0; // false |
| const std::vector<uint16_t> config{{oobPprEnable, RtToBt, BtSetToHard}}; |
| |
| EXPECT_CALL( |
| *managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const std::vector<uint16_t>&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "getPostPackageRepairConfig")) |
| .Times(testing::AtMost(1)) |
| .WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction< |
| std::vector<uint16_t>>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<std::vector<uint16_t>>(config))); |
| |
| handlePPRConfigGet(app_, CreateRequest(), share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json["@odata.id"], "/redfish/v1/Systems/system/LogServices" |
| "/PostPackageRepair/Config"); |
| |
| EXPECT_GT(json["Members@odata.count"], 0); |
| EXPECT_TRUE(json["Members"][0].contains("OobPprEnable")); |
| EXPECT_TRUE(json["Members"][0].contains("autoScheduleRtAsBtPpr")); |
| EXPECT_TRUE(json["Members"][0].contains("autoScheduleBtAsHard")); |
| EXPECT_EQ(json["Members"][0]["OobPprEnable"], true); |
| EXPECT_EQ(json["Members"][0]["autoScheduleRtAsBtPpr"], false); |
| EXPECT_EQ(json["Members"][0]["autoScheduleBtAsHard"], false); |
| } |
| |
| TEST_F(SnapshotFixture, FailedSetPostPackageConfig) |
| { |
| const uint16_t flag = 0x01; // kBtSetToHardMask |
| const bool data = true; |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const bool&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "setPostPackageRepairConfig", flag, data)) |
| .Times(testing::AtMost(1)) |
| .WillOnce( |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction:: |
| SimulateFailedAsyncPostDbusCallWithEmptyValue()); |
| |
| setPostPackageRepairConfig(share_async_resp_, flag, data); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, SuccessfullyhandlePPRConfigPatch) |
| { |
| EXPECT_CALL(*managedStore::GetManagedObjectStore(), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void(const boost::system::error_code&, |
| const bool&)>&&>(), |
| pprFileObject, pprFilePath, pprFileInterface, |
| "setPostPackageRepairConfig", 0x02, false)) |
| .Times(testing::AtMost(1)) |
| .WillOnce( |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction<bool>:: |
| SimulateSuccessfulAsyncPostDbusCallWithValue( |
| std::make_shared<bool>(true))); |
| |
| handlePPRConfigPatch(app_, CreateRequest(pprConfigRequestJson), |
| share_async_resp_); |
| |
| // Wait Dbus call complete |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| #endif // BMCWEB_ENABLE_PPR |
| |
| std::shared_ptr<ValueType> CreateMockFaultLogCPEREntry(){ |
| ManagedObjectType mockFaultLogEntry{ |
| { |
| std::make_pair( |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump/faultlog/entry/2"), |
| DBusInteracesMap{{ |
| // First Mock Completed Status |
| std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Status", |
| "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" |
| ) |
| }} |
| ), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Type", |
| "xyz.openbmc_project.Common.FaultLogType.FaultLogTypes.Crashdump" |
| ), |
| std::make_pair( |
| "PrimaryLogId", |
| "2" |
| ) |
| }} |
| ) |
| }} |
| ) |
| }, |
| { |
| std::make_pair( |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump/faultlog/entry/1"), |
| DBusInteracesMap{{ |
| // First Mock Completed Status |
| std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Status", |
| "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" |
| ) |
| }} |
| ), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Type", |
| "xyz.openbmc_project.Common.FaultLogType.FaultLogTypes.CPER" |
| ), |
| std::make_pair( |
| "PrimaryLogId", |
| "1" |
| ) |
| }} |
| ) |
| }} |
| ) |
| }, |
| }; |
| return managedStore::MockManagedStoreTest::CreateValueType(std::move(mockFaultLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, QueryCrashDumpCollectionExpansion){ |
| KeyType key1(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key1, CreateMockFaultLogCPEREntry()).ok()); |
| |
| query_param::Query delegatedQuery; |
| delegatedQuery.expandLevel = 2; |
| |
| std::string_view fileContent = "Q1BFUgEB/////wEAAgAAA"; |
| BMCWEB_ROUTE( |
| app_, |
| "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/") |
| .privileges({{"ConfigureComponents"}}) |
| .methods(boost::beast::http::verb::get)( |
| [this, &fileContent](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& systemName) |
| { |
| if (!redfish::setUpRedfishRoute(app_, req, asyncResp)) |
| { |
| return; |
| } |
| boost::asio::post(GetStaticIoContext(), |
| [this, &fileContent, &req, asyncResp, systemName]() { |
| nlohmann::json& thisEntry = asyncResp->res.jsonValue; |
| thisEntry["@odata.id"] = "/redfish/v1/Systems/" + systemName + "/LogServices/Crashdump/Entries"; |
| thisEntry["@odata.type"] = "#LogEntryCollection.LogEntryCollection"; |
| thisEntry["Description"] = "Collection of Host Dump Entries"; |
| thisEntry["Members"] = nlohmann::json::array(); |
| thisEntry["Members@odata.count"] = 1; |
| thisEntry["Name"] = "Host Dump Entries"; |
| |
| nlohmann::json dumpEntry; |
| dumpEntry["@odata.id"] = "/redfish/v1/Systems/" + systemName + "/LogServices/Crashdump/Entries/2"; |
| dumpEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; |
| dumpEntry["Created"] = "2024-08-26T20:21:09.735414+00:00"; |
| dumpEntry["DiagnosticData"] = fileContent; |
| dumpEntry["DiagnosticDataType"] = "OpenBMC Fault Log"; |
| dumpEntry["EntryType"] = "Oem"; |
| dumpEntry["Id"] = "2"; |
| dumpEntry["AdditionalDataURI"] = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/2"; |
| dumpEntry["Name"] = "FaultLog Dump Entry"; |
| dumpEntry["OemRecordFormat"] = "Crashdump"; |
| thisEntry["Members"].push_back(std::move(dumpEntry)); |
| }); |
| }); |
| |
| BMCWEB_ROUTE( |
| app_, |
| "/redfish/v1/Systems/<str>/LogServices/HostCper/Entries/") |
| .privileges({{"ConfigureComponents"}}) |
| .methods(boost::beast::http::verb::get)( |
| [this, &fileContent](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, |
| const std::string& systemId) |
| { |
| if (!redfish::setUpRedfishRoute(app_, req, asyncResp)) |
| { |
| return; |
| } |
| boost::asio::post(GetStaticIoContext(), |
| [this, &fileContent, &req, asyncResp, systemId]() { |
| nlohmann::json& thisEntry = asyncResp->res.jsonValue; |
| thisEntry["@odata.id"] = "/redfish/v1/Systems/" + systemId + "/LogServices/HostCper/Entries"; |
| thisEntry["@odata.type"] = "#LogEntryCollection.LogEntryCollection"; |
| thisEntry["Description"] = "Collection of Host CPER Entries"; |
| thisEntry["Members"] = nlohmann::json::array(); |
| thisEntry["Members@odata.count"] = 1; |
| thisEntry["Name"] = "Host CPER Entries"; |
| |
| nlohmann::json hostCperEntry; |
| hostCperEntry["@odata.id"] = "/redfish/v1/Systems/" + systemId + |
| "/LogServices/HostCper/Entries/1"; |
| hostCperEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry"; |
| hostCperEntry["Created"] = "2024-08-26T20:21:09.735414+00:00"; |
| hostCperEntry["DiagnosticData"] = fileContent; |
| hostCperEntry["DiagnosticDataType"] = "CPER"; |
| hostCperEntry["EntryType"] = "Oem"; |
| hostCperEntry["Id"] = "1"; |
| hostCperEntry["Name"] = "Host CPER Entry"; |
| thisEntry["Members"].push_back(std::move(hostCperEntry)); |
| }); |
| } |
| ); |
| app_.validate(); |
| |
| getDumpEntryCollection(app_, CreateRequest(), |
| share_async_resp_, Dump{.type = DumpType::BMC_FAULT_LOG}, delegatedQuery); |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json["@odata.id"], |
| "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries"); |
| EXPECT_EQ(json["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(json["Description"], "Collection of FaultLog Dump Entries"); |
| EXPECT_EQ(json["Name"], "FaultLog Dump Entries"); |
| EXPECT_EQ(json["Members"].size(), json["Members@odata.count"]); |
| |
| // Expected data. from odata.id : {field : value}. |
| // Example: |
| // - /redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/2: |
| // - id: 2 |
| // - OemRecordFormat: Crashdump |
| std::unordered_map<std::string, |
| std::unordered_map<std::string, std::string>> expectedData = { |
| { |
| "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/2", { |
| {"Id", "2"}, |
| {"OemRecordFormat", "Crashdump"}, |
| } |
| }, |
| { |
| "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/1", { |
| {"Id", "1"}, |
| {"OemRecordFormat", "CPER"}, |
| } |
| } |
| }; |
| |
| EXPECT_TRUE(json.contains("Members")); |
| EXPECT_EQ(json["Members"].size(), 2); |
| for (auto& member : json["Members"]) |
| { |
| std::string odataId = member["@odata.id"]; |
| EXPECT_TRUE(expectedData.contains(odataId)); |
| auto& data = expectedData[odataId]; |
| EXPECT_EQ(member["Id"], data["Id"]); |
| EXPECT_EQ(member["OemRecordFormat"], data["OemRecordFormat"]); |
| } |
| } |
| |
| std::shared_ptr<ValueType> CreateMockBMCDumpEntry(){ |
| ManagedObjectType mockFaultLogEntry{ |
| { |
| std::make_pair( |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump/bmc/entry/1"), |
| DBusInteracesMap{{ |
| std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Status", |
| "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" |
| ) |
| }} |
| ), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Size", |
| BMC_DUMP_SIZE |
| ) |
| }} |
| ) |
| }} |
| ) |
| }, |
| }; |
| return managedStore::MockManagedStoreTest::CreateValueType(std::move(mockFaultLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, QueryBMCDumpCollectionExpansion) |
| { |
| KeyType key1(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key1, CreateMockBMCDumpEntry()).ok()); |
| |
| query_param::Query delegatedQuery; |
| delegatedQuery.expandLevel = 2; |
| getDumpEntryCollection(app_, CreateRequest(), |
| share_async_resp_, Dump{.type = DumpType::BMC_DUMP}, delegatedQuery); |
| RunIoUntilDone(); |
| |
| nlohmann::json& resp = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(resp["@odata.id"], |
| "/redfish/v1/Managers/bmc/LogServices/Dump/Entries"); |
| EXPECT_EQ(resp["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(resp["Description"], "Collection of BMC Dump Entries"); |
| EXPECT_EQ(resp["Members"].size(), resp["Members@odata.count"]); |
| |
| EXPECT_EQ(resp["Members"].size(), 1); |
| auto& member = resp["Members"][0]; |
| EXPECT_EQ(member["AdditionalDataSizeBytes"], BMC_DUMP_SIZE); |
| EXPECT_EQ(member["EntryType"], "Event"); |
| EXPECT_EQ(member["Name"], "BMC Dump Entry"); |
| EXPECT_EQ(member["DiagnosticDataType"], "Manager"); |
| EXPECT_EQ(member["AdditionalDataURI"], |
| "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/1/attachment"); |
| } |
| |
| std::shared_ptr<ValueType> CreateMockSystemDumpEntry(){ |
| ManagedObjectType mockFaultLogEntry{ |
| { |
| std::make_pair( |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump/system/entry/1"), |
| DBusInteracesMap{{ |
| std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Status", |
| "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" |
| ) |
| }} |
| ), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry", |
| DBusPropertiesMap{{ |
| std::make_pair( |
| "Size", |
| BMC_DUMP_SIZE |
| ) |
| }} |
| ) |
| }} |
| ) |
| }, |
| }; |
| return managedStore::MockManagedStoreTest::CreateValueType(std::move(mockFaultLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, QuerySystemDumpCollectionExpansion) |
| { |
| KeyType key1(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(managedStore::GetManagedObjectStore() |
| ->upsertMockObjectIntoManagedStore(key1, CreateMockSystemDumpEntry()).ok()); |
| |
| query_param::Query delegatedQuery; |
| delegatedQuery.expandLevel = 2; |
| getDumpEntryCollection(app_, CreateRequest(), |
| share_async_resp_, Dump{.type = DumpType::SYSTEM_DUMP}, delegatedQuery); |
| RunIoUntilDone(); |
| |
| nlohmann::json& resp = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(resp["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/Dump/Entries"); |
| EXPECT_EQ(resp["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(resp["Description"], "Collection of System Dump Entries"); |
| EXPECT_EQ(resp["Members"].size(), resp["Members@odata.count"]); |
| |
| EXPECT_EQ(resp["Members"].size(), 1); |
| auto& member = resp["Members"][0]; |
| EXPECT_EQ(member["AdditionalDataSizeBytes"], BMC_DUMP_SIZE); |
| EXPECT_EQ(member["EntryType"], "Event"); |
| EXPECT_EQ(member["Name"], "System Dump Entry"); |
| EXPECT_EQ(member["OEMDiagnosticDataType"], "System"); |
| } |
| |
| } // namespace |
| } // namespace redfish |