| #include "log_services.hpp" |
| |
| #include <array> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdio> |
| #include <filesystem> // NOLINT |
| #include <fstream> |
| #include <functional> |
| #include <iostream> |
| #include <map> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <string_view> |
| #include <tuple> |
| #include <unordered_map> |
| #include <utility> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include "absl/functional/any_invocable.h" |
| #include "app.hpp" |
| #include "http_request.hpp" |
| #include "utility.hpp" |
| #include "async_resp.hpp" |
| #include "dbus_utility.hpp" |
| #include "query.hpp" |
| #include "registries/privilege_registry.hpp" |
| #include "health.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" |
| #include "sdbusplus/message/native_types.hpp" |
| |
| 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::ManagedType; |
| using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeAction; |
| using ::managedStore:: |
| SimulateFailedAsyncPostDbusCallThreadSafeWithEmptyValueAction; |
| using ::managedStore:: |
| SimulateSuccessfulAsyncPostDbusCallThreadSafeWithValueAction; |
| 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; |
| constexpr std::array<std::string_view, 1> kSystemInterfaces = { |
| "xyz.openbmc_project.Inventory.Item.System"}; |
| |
| 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( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore(key, mockIsRebooting) |
| .ok()); |
| } else { |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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_GT(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 |
| // NOLINTNEXTLINE(runtime/string) |
| 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( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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/Oem/Amd/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(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| setProperty(pprFileObject, pprFilePath, pprFileInterface, "RecordAdd", |
| dbus::utility::DbusVariantType{true}, _)) |
| .Times(1) |
| .WillOnce(SimulateFailedAsyncSetPropertyDbusCallAction:: |
| SimulateFailedAsyncSetPropertyDbusCall()); |
| return; |
| } |
| EXPECT_CALL(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| setProperty(pprFileObject, pprFilePath, pprFileInterface, |
| "RecordAdd", dbus::utility::DbusVariantType{true}, _)) |
| .Times(1) |
| .WillOnce(SimulateSuccessfulAsyncSetPropertyDbusCallAction:: |
| SimulateSuccessfulAsyncSetPropertyDbusCall()); |
| if (dbusException >= 1) { |
| EXPECT_CALL(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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, FailedOobPprEnableHandlePPRFilePost) { |
| // 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(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore(key, oobPprEnable) |
| .ok()); |
| |
| handlePPRFilePost(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, SuccessfullyHandlePPRFilePost) { |
| KeyType key(ManagedType::kManagedProperty, pprFileObject, |
| sdbusplus::message::object_path(pprFilePath), pprFileInterface, |
| "oobPprEnable"); |
| std::shared_ptr<ValueType> oobPprEnable = |
| CreateValueType(DbusVariantType(true)); |
| |
| EXPECT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore(key, oobPprEnable) |
| .ok()); |
| |
| prepareSetPostPackageRepairDataExpectCall(0); |
| |
| handlePPRFilePost(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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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" |
| "/Oem/Amd/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(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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, SuccessfullyhandlePPRConfigPost) { |
| EXPECT_CALL(*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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))); |
| |
| handlePPRConfigPost(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", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("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", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair("Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.CPER"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("1")))}})}})}, |
| }; |
| return managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry)); |
| } |
| |
| std::shared_ptr<ValueType> CreateMockFaultLogMetisCPEREntry() { |
| std::string primaryLogId = |
| (std::filesystem::temp_directory_path() / "mock_metis_cper.bin").string(); |
| ManagedObjectType mockFaultLogEntry{{std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{ |
| // Completed Status |
| {std::make_pair("xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")}})}, |
| // OriginatedBy |
| {std::make_pair( |
| "xyz.openbmc_project.Common.OriginatedBy", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "OriginatorId", |
| "/redfish/v1/Chassis/Humubeach/PCIeDevices/Metis_0"), |
| std::make_pair("OriginatorType", |
| "xyz.openbmc_project.Common.OriginatedBy." |
| "OriginatorTypes.Client")}})}, |
| // FaultLog entry properties |
| {std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair("Type", |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.MetisCPER"), |
| std::make_pair("PrimaryLogId", primaryLogId)}})}})}}; |
| return managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, |
| LogServiceFaultLogEntriesGetMetisCPERSuccessfulResponse) { |
| std::string systemId = "system1"; |
| KeyType key(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| key, CreateMockFaultLogMetisCPEREntry()) |
| .ok()); |
| |
| handleLogServiceFaultLogEntriesGet(app_, CreateRequest(), share_async_resp_, |
| systemId); |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json["Members@odata.count"], 1); |
| nlohmann::json& faultLog1 = json["Members"][0]; |
| EXPECT_EQ(faultLog1["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(faultLog1["DiagnosticDataType"], "OEM"); |
| EXPECT_EQ(faultLog1["AdditionalDataURI"], |
| "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(faultLog1["OEMDiagnosticDataType"], "MetisCPER"); |
| EXPECT_EQ(faultLog1["OemRecordFormat"], "MetisCPER"); |
| EXPECT_EQ(faultLog1["Links"]["OriginOfCondition"]["@odata.id"], |
| "/redfish/v1/Chassis/Humubeach/PCIeDevices/Metis_0"); |
| EXPECT_EQ(faultLog1["Links"]["RelatedLogEntries"][0]["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, |
| LogServiceFaultLogEntryByIdMetisCPERSuccessfulResponse) { |
| std::string systemId = "system1"; |
| KeyType key(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| key, CreateMockFaultLogMetisCPEREntry()) |
| .ok()); |
| |
| std::filesystem::path attachmentPath = |
| std::filesystem::temp_directory_path() / "mock_metis_cper.bin"; |
| std::ofstream ofs(attachmentPath, std::ios::out | std::ios::binary); |
| ASSERT_TRUE(ofs.is_open()); |
| std::string_view expectedData = "BinaryMetisCPERPayload_0123456789"; |
| ofs.write(expectedData.data(), static_cast<int>(expectedData.size())); |
| ofs.close(); |
| |
| getDumpEntryById( |
| share_async_resp_, "1", |
| Dump{.type = DumpType::SYSTEM_FAULT_LOG, .systemName = systemId}); |
| RunIoUntilDone(); |
| |
| nlohmann::json& faultLog1 = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(faultLog1["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(faultLog1["DiagnosticDataType"], "OEM"); |
| EXPECT_EQ(faultLog1["AdditionalDataURI"], |
| "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(faultLog1["OEMDiagnosticDataType"], "MetisCPER"); |
| EXPECT_EQ(faultLog1["OemRecordFormat"], "MetisCPER"); |
| EXPECT_EQ(faultLog1["Links"]["OriginOfCondition"]["@odata.id"], |
| "/redfish/v1/Chassis/Humubeach/PCIeDevices/Metis_0"); |
| EXPECT_EQ(faultLog1["Links"]["RelatedLogEntries"][0]["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1"); |
| EXPECT_EQ(faultLog1["DiagnosticData"], |
| "QmluYXJ5TWV0aXNDUEVSUGF5bG9hZF8wMTIzNDU2Nzg5"); |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| |
| std::filesystem::remove(attachmentPath); |
| } |
| |
| TEST_F(SnapshotFixture, QueryCrashDumpCollectionExpansion) { |
| KeyType key1(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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(), [&fileContent, 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/dumpmanager_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(), [&fileContent, 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> CreateMockFaultLogMixedCrashdumpEntries() { |
| ManagedObjectType mockFaultLogEntry{ |
| // System-specific entry for system1 |
| // (/xyz/openbmc_project/dump/faultlog/0/entry/1) |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("1")))}})}})}, |
| // System-agnostic entry (/xyz/openbmc_project/dump/faultlog/entry/2) |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/2"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("2")))}})}})}, |
| // System-specific entry for system2 |
| // (/xyz/openbmc_project/dump/faultlog/1/entry/3) |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/1/entry/3"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("3")))}})}})}, |
| }; |
| return managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, |
| LogServiceFaultLogEntriesGetSystemSpecificWithPrefixes) { |
| std::string systemId = "system1"; |
| KeyType key(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| key, CreateMockFaultLogMixedCrashdumpEntries()) |
| .ok()); |
| |
| handleLogServiceFaultLogEntriesGet(app_, CreateRequest(), share_async_resp_, |
| systemId); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries", |
| "@odata.type": "#LogEntryCollection.LogEntryCollection", |
| "Description": "Collection of FaultLog Dump Entries", |
| "Members": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_1", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Links": { |
| "RelatedLogEntries": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_1" |
| } |
| ] |
| }, |
| "Name": "FaultLog Dump Entry", |
| "OEMDiagnosticDataType": "OpenBMC Fault Log", |
| "OemRecordFormat": "Crashdump" |
| } |
| ], |
| "Members@odata.count": 1, |
| "Name": "FaultLog Dump Entries" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, LogServiceFaultLogEntryByIdSystemSpecificOnly) { |
| std::string systemId = "system1"; |
| KeyType key(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| key, CreateMockFaultLogMixedCrashdumpEntries()) |
| .ok()); |
| |
| // 1. Fetch system1-specific entry "1" -> 200 OK with prefix |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| getDumpEntryById( |
| asyncResp, "1", |
| Dump{.type = DumpType::SYSTEM_FAULT_LOG, .systemName = systemId}); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/FaultLog/Entries/1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_1", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Links": { |
| "RelatedLogEntries": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_1" |
| } |
| ] |
| }, |
| "Name": "FaultLog Dump Entry", |
| "OEMDiagnosticDataType": "OpenBMC Fault Log", |
| "OemRecordFormat": "Crashdump" |
| })"); |
| EXPECT_EQ(asyncResp->res.jsonValue, expectedJson); |
| } |
| |
| // 2. Fetch system-agnostic entry "2" via system1 -> should be 404 (skipped) |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| getDumpEntryById( |
| asyncResp, "2", |
| Dump{.type = DumpType::SYSTEM_FAULT_LOG, .systemName = systemId}); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::not_found); |
| } |
| |
| // 3. Fetch entry "3" (which belongs to system2) via system1 -> should be 404 |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| getDumpEntryById( |
| asyncResp, "3", |
| Dump{.type = DumpType::SYSTEM_FAULT_LOG, .systemName = systemId}); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::not_found); |
| } |
| } |
| |
| TEST_F(SnapshotFixture, LogServiceFaultLogEntriesGetSystem2Isolation) { |
| std::string systemId = "system2"; |
| KeyType key(ManagedType::kManagedObject, "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| key, CreateMockFaultLogMixedCrashdumpEntries()) |
| .ok()); |
| |
| handleLogServiceFaultLogEntriesGet(app_, CreateRequest(), share_async_resp_, |
| systemId); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system2/LogServices/FaultLog/Entries", |
| "@odata.type": "#LogEntryCollection.LogEntryCollection", |
| "Description": "Collection of FaultLog Dump Entries", |
| "Members": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system2/LogServices/FaultLog/Entries/3", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system2/LogServices/Crashdump/Entries/dumpmanager_system2_3", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "3", |
| "Links": { |
| "RelatedLogEntries": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system2/LogServices/Crashdump/Entries/dumpmanager_system2_3" |
| } |
| ] |
| }, |
| "Name": "FaultLog Dump Entry", |
| "OEMDiagnosticDataType": "OpenBMC Fault Log", |
| "OemRecordFormat": "Crashdump" |
| } |
| ], |
| "Members@odata.count": 1, |
| "Name": "FaultLog Dump Entries" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| std::shared_ptr<ValueType> CreateMockSingleSystemFaultLogEntry( |
| const std::string& logFilePath = "") { |
| DBusPropertiesMap faultLogProps{ |
| {std::make_pair("Type", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", DbusVariantType(std::string("1")))}}; |
| if (!logFilePath.empty()) { |
| faultLogProps.emplace_back("Log", DbusVariantType(logFilePath)); |
| } |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/1"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair("xyz.openbmc_project.Dump.Entry.FaultLog", |
| std::move(faultLogProps))}})}, |
| }; |
| return managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry)); |
| } |
| |
| TEST_F(SnapshotFixture, SingleSystemFaultLogAndCrashdumpExposedCorrectly) { |
| std::string systemId = "system"; |
| |
| // Mock system inventory path for single-system |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| // Create temporary crashdump log file |
| std::filesystem::path tempLogFile = std::filesystem::temp_directory_path() / |
| "test_single_system_crashdump.bin"; |
| { |
| std::ofstream ofs(tempLogFile, std::ios::binary); |
| ofs << "CrashdumpPayload123"; |
| } |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, |
| CreateMockSingleSystemFaultLogEntry(tempLogFile.string())) |
| .ok()); |
| |
| // 1. FaultLog Collection GET -> |
| // /redfish/v1/Systems/system/LogServices/FaultLog/Entries |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| handleLogServiceFaultLogEntriesGet(app_, CreateRequest(), asyncResp, |
| systemId); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/FaultLog/Entries", |
| "@odata.type": "#LogEntryCollection.LogEntryCollection", |
| "Description": "Collection of FaultLog Dump Entries", |
| "Members": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/FaultLog/Entries/1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Links": { |
| "RelatedLogEntries": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1" |
| } |
| ] |
| }, |
| "Name": "FaultLog Dump Entry", |
| "OEMDiagnosticDataType": "OpenBMC Fault Log", |
| "OemRecordFormat": "Crashdump" |
| } |
| ], |
| "Members@odata.count": 1, |
| "Name": "FaultLog Dump Entries" |
| })"); |
| EXPECT_EQ(asyncResp->res.jsonValue, expectedJson); |
| } |
| |
| // 2. FaultLog Entry By ID GET -> |
| // /redfish/v1/Systems/system/LogServices/FaultLog/Entries/1 |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| getDumpEntryById( |
| asyncResp, "1", |
| Dump{.type = DumpType::SYSTEM_FAULT_LOG, .systemName = systemId}); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/FaultLog/Entries/1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Links": { |
| "RelatedLogEntries": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1" |
| } |
| ] |
| }, |
| "Name": "FaultLog Dump Entry", |
| "OEMDiagnosticDataType": "OpenBMC Fault Log", |
| "OemRecordFormat": "Crashdump" |
| })"); |
| EXPECT_EQ(asyncResp->res.jsonValue, expectedJson); |
| } |
| |
| // 3. Crashdump Collection GET -> |
| // /redfish/v1/Systems/system/LogServices/Crashdump/Entries |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), asyncResp, |
| systemId); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries", |
| "@odata.type": "#LogEntryCollection.LogEntryCollection", |
| "Description": "Collection of Crashdump Entries", |
| "Members": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticData": "Q3Jhc2hkdW1wUGF5bG9hZDEyMw==", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Name": "Host Crashdump Entry" |
| } |
| ], |
| "Members@odata.count": 1, |
| "Name": "Crashdump Entries" |
| })"); |
| EXPECT_EQ(asyncResp->res.jsonValue, expectedJson); |
| } |
| |
| // 4. Crashdump Entry By ID GET -> |
| // /redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1 |
| { |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); |
| handleGetCrashdumpEntry(app_, CreateRequest(), asyncResp, systemId, |
| "dumpmanager_1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/dumpmanager_1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticData": "Q3Jhc2hkdW1wUGF5bG9hZDEyMw==", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Name": "Host Crashdump Entry" |
| })"); |
| EXPECT_EQ(asyncResp->res.jsonValue, expectedJson); |
| } |
| |
| std::filesystem::remove(tempLogFile); |
| } |
| |
| 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( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| 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"); |
| } |
| |
| TEST_F(SnapshotFixture, HealthMonitorLogServiceGetSuccess) { |
| // Mock the D-Bus call to getSubTreePaths to simulate a single-host |
| // environment where "system" is a valid system name. |
| KeyType key(ManagedType::kManagedSubtreePaths, |
| "/xyz/openbmc_project/inventory", 0, |
| {"xyz.openbmc_project.Inventory.Item.System"}); |
| |
| MapperGetSubTreePathsResponse mockResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| std::shared_ptr<ValueType> mockValue = |
| CreateValueType(std::move(mockResponse)); |
| |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore(key, mockValue) |
| .ok()); |
| |
| const std::string systemName = "system"; |
| // Call the newly created handler function |
| handleHealthMonitorLogServiceGet(app_, CreateRequest(), share_async_resp_, |
| systemName); |
| |
| RunIoUntilDone(); |
| |
| // Verify the response |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| const std::string odataId = |
| "/redfish/v1/Systems/system/LogServices/HealthMonitor"; |
| |
| EXPECT_EQ(json["@odata.id"], odataId); |
| EXPECT_EQ(json["@odata.type"], "#LogService.v1_1_0.LogService"); |
| EXPECT_EQ(json["Name"], "Health Monitor Log Service"); |
| EXPECT_EQ(json["Description"], "Health Monitor Log Service"); |
| EXPECT_EQ(json["Id"], "HealthMonitor"); |
| EXPECT_EQ(json["Entries"]["@odata.id"], odataId + "/Entries"); |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, HealthMonitorLogEntryCollectionGetSuccess) { |
| // Clean up the singleton for other tests. |
| HealthStatusCache::getInstance().clear(); |
| // Part 1: Populate the HealthStatusCache with a mock entry. |
| // This requires mocking the D-Bus objects that the HealthStatusCache |
| // constructor and getHealthAttributes() would normally read. |
| |
| // Mock the initial discovery of health monitor configurations. |
| const std::string healthMonitorPath = |
| "/xyz/openbmc_project/inventory/system/board/CPU_0/Temp"; |
| const MapperGetSubTreePathsResponse mockSubTreePaths = {healthMonitorPath}; |
| KeyType subTreeKey(ManagedType::kManagedSubtreePaths, |
| "/xyz/openbmc_project/inventory", 0, |
| {"xyz.openbmc_project.Configuration.HealthMonitor"}); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| subTreeKey, CreateValueType(std::move(mockSubTreePaths))) |
| .ok()); |
| |
| // Mock the properties of the health monitor configuration itself. |
| DBusPropertiesMap configProperties{ |
| {"Name", DbusVariantType("Temp")}, |
| {"Severity", DbusVariantType("Critical")}, |
| {"FailureMessageId", |
| DbusVariantType("ResourceEvent.1.0.ResourceErrorsDetected")}, |
| {"OkMessageId", |
| DbusVariantType("ResourceEvent.1.0.ResourceErrorsCorrected")}, |
| {"MessageArgs", |
| DbusVariantType(std::vector<std::string>{"CPU_0", "Temperature"})}, |
| {"Resolution", DbusVariantType("None")}, |
| {"RelatedEntityName", DbusVariantType("CPU_0")}, |
| {"RelatedEntityType", DbusVariantType("Processor")}, |
| }; |
| KeyType configKey(ManagedType::kManagedPropertyMap, |
| "xyz.openbmc_project.EntityManager", |
| sdbusplus::message::object_path(healthMonitorPath), |
| "xyz.openbmc_project.Configuration.HealthMonitor"); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| configKey, CreateValueType(std::move(configProperties))) |
| .ok()); |
| |
| // Mock the current health status (unhealthy in this case). |
| DBusPropertiesMap statusProperties{ |
| {"healthy", DbusVariantType(false)}, |
| {"toggle_count", DbusVariantType(uint64_t{1})}}; |
| sdbusplus::message::object_path statusPath( |
| "/xyz/openbmc_project/HealthMonitor/Temp"); |
| KeyType statusKey(ManagedType::kManagedPropertyMap, |
| "xyz.openbmc_project.HealthMonitor", statusPath, |
| "xyz.openbmc_project.HealthMonitor.GetStatus"); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| statusKey, CreateValueType(std::move(statusProperties))) |
| .ok()); |
| |
| // Trigger the cache to populate itself with the mock data. |
| HealthStatusCache::getInstance().getHealthAttributes(healthMonitorPath); |
| RunIoUntilDone(); // Ensure async D-Bus calls within getHealthAttributes |
| // complete. |
| |
| // Part 2: Mock the system path validation. |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, |
| "/xyz/openbmc_project/inventory", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| // Part 3: Call the handler and verify the response. |
| const std::string systemName = "system"; |
| handleHealthMonitorLogEntryCollectionGet(app_, CreateRequest(), |
| share_async_resp_, systemName); |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| const std::string odataId = |
| "/redfish/v1/Systems/system/LogServices/HealthMonitor/Entries"; |
| |
| EXPECT_EQ(json["@odata.id"], odataId); |
| EXPECT_EQ(json["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(json["Name"], "Health Monitor Log Entries"); |
| EXPECT_EQ(json["Members@odata.count"], 1); |
| ASSERT_EQ(json["Members"].size(), 1); |
| |
| // Verify the content of the log entry. |
| const nlohmann::json& logEntry = json["Members"][0]; |
| EXPECT_EQ(logEntry["Id"], "0"); |
| EXPECT_EQ(logEntry["Severity"], "Critical"); |
| EXPECT_EQ(logEntry["Resolved"], false); |
| EXPECT_EQ(logEntry["MessageId"], "ResourceEvent.1.0.ResourceErrorsDetected"); |
| EXPECT_EQ( |
| logEntry["Message"], |
| "The resource property CPU_0 has detected errors of type Temperature"); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| |
| // Clean up the singleton for other tests. |
| HealthStatusCache::getInstance().clear(); |
| } |
| |
| TEST_F(SnapshotFixture, HealthMonitorLogEntryGetSuccess) { |
| // FIX: Clear both the cache and the underlying mock D-Bus store. |
| HealthStatusCache::getInstance().clear(); |
| |
| // Part 1: Populate the HealthStatusCache with a mock entry. |
| const std::string healthMonitorPath = |
| "/xyz/openbmc_project/inventory/system/board/CPU_0/Temp"; |
| const MapperGetSubTreePathsResponse mockSubTreePaths = {healthMonitorPath}; |
| KeyType subTreeKey(ManagedType::kManagedSubtreePaths, |
| "/xyz/openbmc_project/inventory", 0, |
| {"xyz.openbmc_project.Configuration.HealthMonitor"}); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| subTreeKey, CreateValueType(std::move(mockSubTreePaths))) |
| .ok()); |
| |
| // In HealthMonitorLogEntryGetSuccess test case |
| DBusPropertiesMap configProperties{ |
| {"Name", DbusVariantType("Temp")}, |
| {"Severity", DbusVariantType("Critical")}, |
| {"FailureMessageId", |
| DbusVariantType("ResourceEvent.1.0.ResourceErrorsDetected")}, |
| {"OkMessageId", |
| DbusVariantType("ResourceEvent.1.0.ResourceErrorsCorrected")}, |
| {"MessageArgs", |
| DbusVariantType(std::vector<std::string>{"CPU_0", "Temperature"})}, |
| {"Resolution", DbusVariantType("None")}, |
| {"RelatedEntityName", DbusVariantType("CPU_0")}, |
| {"RelatedEntityType", DbusVariantType("Processor")}, |
| }; |
| |
| KeyType configKey(ManagedType::kManagedPropertyMap, |
| "xyz.openbmc_project.EntityManager", |
| sdbusplus::message::object_path(healthMonitorPath), |
| "xyz.openbmc_project.Configuration.HealthMonitor"); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| configKey, CreateValueType(std::move(configProperties))) |
| .ok()); |
| |
| DBusPropertiesMap statusProperties{ |
| {"healthy", DbusVariantType(false)}, |
| {"toggle_count", DbusVariantType(uint64_t{1})}}; |
| sdbusplus::message::object_path statusPath( |
| "/xyz/openbmc_project/HealthMonitor/Temp"); |
| KeyType statusKey(ManagedType::kManagedPropertyMap, |
| "xyz.openbmc_project.HealthMonitor", statusPath, |
| "xyz.openbmc_project.HealthMonitor.GetStatus"); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| statusKey, CreateValueType(std::move(statusProperties))) |
| .ok()); |
| |
| HealthStatusCache::getInstance().getHealthAttributes(healthMonitorPath); |
| RunIoUntilDone(); |
| |
| // Part 2: Mock the system path validation. |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, |
| "/xyz/openbmc_project/inventory", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| // Part 3: Call the handler for a single entry and verify the response. |
| const std::string systemName = "system"; |
| const std::string entryId = "0"; // Request the first log entry |
| handleHealthMonitorLogEntryGet(app_, CreateRequest(), share_async_resp_, |
| systemName, entryId); |
| RunIoUntilDone(); |
| |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| |
| // Verify it's a single LogEntry object, not a collection |
| EXPECT_EQ(json["@odata.type"], "#LogEntry.v1_9_0.LogEntry"); |
| EXPECT_EQ(json["Id"], "0"); |
| EXPECT_EQ(json["Severity"], "Critical"); |
| EXPECT_EQ(json["Resolved"], false); |
| EXPECT_EQ(json["MessageId"], "ResourceEvent.1.0.ResourceErrorsDetected"); |
| EXPECT_EQ( |
| json["Message"], |
| "The resource property CPU_0 has detected errors of type Temperature"); |
| |
| // Ensure it's not a collection |
| EXPECT_FALSE(json.contains("Members")); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| |
| HealthStatusCache::getInstance().clear(); |
| } |
| |
| TEST_F(SnapshotFixture, GetSystemLogServicesCollectionSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| KeyType postCodeKey( |
| ManagedType::kManagedSubtreePaths, "/", 0, |
| std::vector<std::string>{"xyz.openbmc_project.State.Boot.PostCode"}); |
| MapperGetSubTreePathsResponse mockPostCodeResponse = { |
| "/xyz/openbmc_project/State/Boot/PostCode0"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| postCodeKey, CreateValueType(mockPostCodeResponse)) |
| .ok()); |
| |
| handleSystemLogServicesCollectionGet(app_, CreateRequest(), share_async_resp_, |
| "system"); |
| 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"); |
| EXPECT_EQ(json["@odata.type"], "#LogServiceCollection.LogServiceCollection"); |
| EXPECT_EQ(json["Name"], "System Log Services Collection"); |
| |
| bool foundCrashdump = false; |
| bool foundPostCodes = false; |
| for (const auto& member : json["Members"]) { |
| if (member["@odata.id"] == |
| "/redfish/v1/Systems/system/LogServices/Crashdump") { |
| foundCrashdump = true; |
| } |
| if (member["@odata.id"] == |
| "/redfish/v1/Systems/system/LogServices/PostCodes") { |
| foundPostCodes = true; |
| } |
| } |
| EXPECT_TRUE(foundCrashdump); |
| EXPECT_TRUE(foundPostCodes); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpServiceSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| handleGetCrashdumpService(app_, CreateRequest(), share_async_resp_, "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& json = share_async_resp_->res.jsonValue; |
| json.erase("DateTime"); |
| json.erase("DateTimeLocalOffset"); |
| |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump", |
| "@odata.type": "#LogService.v1_2_0.LogService", |
| "Actions": { |
| "#LogService.ClearLog": { |
| "target": "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog" |
| }, |
| "#LogService.CollectDiagnosticData": { |
| "target": "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData" |
| } |
| }, |
| "Description": "Crashdump Service", |
| "Entries": { |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries" |
| }, |
| "Id": "Crashdump", |
| "Name": "Crashdump Service", |
| "OverWritePolicy": "WrapsWhenFull" |
| })"); |
| EXPECT_EQ(json, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpServiceFailure) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| handleGetCrashdumpService(app_, CreateRequest(), share_async_resp_, "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryCollectionSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| std::vector<std::string> mockCrashdumpPaths = {"/com/intel/crashdump/log1"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, CreateValueType(mockCrashdumpPaths)) |
| .ok()); |
| |
| DBusPropertiesMap crashdumpProperties{ |
| {"Filename", DbusVariantType("crash_log_file")}, |
| {"Timestamp", DbusVariantType("2026-07-31T22:00:00Z")}, |
| {"Log", DbusVariantType("crash_filepath")}, |
| }; |
| KeyType crashPropertiesKey( |
| ManagedType::kManagedPropertyMap, "com.intel.crashdump", |
| sdbusplus::message::object_path("/com/intel/crashdump/log1"), |
| "com.intel.crashdump"); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashPropertiesKey, |
| CreateValueType(std::move(crashdumpProperties))) |
| .ok()); |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries", |
| "@odata.type": "#LogEntryCollection.LogEntryCollection", |
| "Description": "Collection of Crashdump Entries", |
| "Members": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/intel_log1", |
| "@odata.type": "#LogEntry.v1_9_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/intel_log1/crash_log_file", |
| "Created": "2026-07-31T22:00:00Z", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "log1", |
| "Name": "CPU Crashdump", |
| "OEMDiagnosticDataType": "PECICrashdump" |
| } |
| ], |
| "Members@odata.count": 1, |
| "Name": "Crashdump Entries" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntrySuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| DBusPropertiesMap crashdumpProperties{ |
| {"Filename", DbusVariantType("crash_log_file")}, |
| {"Timestamp", DbusVariantType("2026-07-31T22:00:00Z")}, |
| {"Log", DbusVariantType("crash_filepath")}, |
| }; |
| KeyType crashPropertiesKey( |
| ManagedType::kManagedPropertyMap, "com.intel.crashdump", |
| sdbusplus::message::object_path("/com/intel/crashdump/log1"), |
| "com.intel.crashdump"); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashPropertiesKey, |
| CreateValueType(std::move(crashdumpProperties))) |
| .ok()); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "intel_log1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/intel_log1", |
| "@odata.type": "#LogEntry.v1_9_0.LogEntry", |
| "AdditionalDataURI": "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/intel_log1/crash_log_file", |
| "Created": "2026-07-31T22:00:00Z", |
| "DiagnosticDataType": "OEM", |
| "EntryType": "Oem", |
| "Id": "log1", |
| "Name": "CPU Crashdump", |
| "OEMDiagnosticDataType": "PECICrashdump" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryFaultLogSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/2"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("2")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_fl"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| { |
| std::ofstream ofs(targetDir + "2", std::ios::binary); |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_system1_2", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_2", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticData": "", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "2", |
| "Name": "Host Crashdump Entry" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryMultiHostSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("1")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_mh1"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| { |
| std::ofstream ofs(targetDir + "1", std::ios::binary); |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_system1_1", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticData": "", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Name": "Host Crashdump Entry" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST(CrashdumpFolderPathTest, CrashdumpFolderPathFromSystemName) { |
| EXPECT_EQ(crashdumpFolderPathFromSystemName("system"), std::nullopt); |
| EXPECT_EQ(crashdumpFolderPathFromSystemName("system1"), |
| "/var/run/pldm/event/repo/host0/Crashdump/"); |
| EXPECT_EQ(crashdumpFolderPathFromSystemName("system2"), |
| "/var/run/pldm/event/repo/host1/Crashdump/"); |
| EXPECT_EQ(crashdumpFolderPathFromSystemName("unknown"), std::nullopt); |
| |
| EXPECT_EQ(crashdumpFolderPathFromSystemName("system1", "/tmp/test"), |
| "/tmp/test/var/run/pldm/event/repo/host0/Crashdump/"); |
| EXPECT_EQ(crashdumpFolderPathFromSystemName("system2", "/tmp/test"), |
| "/tmp/test/var/run/pldm/event/repo/host1/Crashdump/"); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryMultiHostWithFileSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("log1.bin")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/crashdump_test_dir"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| std::string filePath = targetDir + "log1.bin"; |
| { |
| std::ofstream ofs(filePath, std::ios::binary); |
| ofs << "test_crashdump_content"; |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_system1_1", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["DiagnosticData"], |
| "dGVzdF9jcmFzaGR1bXBfY29udGVudA=="); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryCollectionMultiHostSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| MapperGetSubTreePathsResponse emptyCrashdumpPaths = {}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, CreateValueType(emptyCrashdumpPaths)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("1")))}})}})}, |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/2"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("2")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_mh2"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| { |
| std::ofstream ofs(targetDir + "1", std::ios::binary); |
| } |
| { |
| std::ofstream ofs(targetDir + "2", std::ios::binary); |
| } |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system1", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries", |
| "@odata.type": "#LogEntryCollection.LogEntryCollection", |
| "Description": "Collection of Crashdump Entries", |
| "Members": [ |
| { |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_1", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticData": "", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "1", |
| "Name": "Host Crashdump Entry" |
| }, |
| { |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_2", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.000000+00:00", |
| "DiagnosticData": "", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "2", |
| "Name": "Host Crashdump Entry" |
| } |
| ], |
| "Members@odata.count": 2, |
| "Name": "Crashdump Entries" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryMissingPropertiesInternalError) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/1"), |
| DBusInteracesMap{{std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair("Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", DbusVariantType(std::string( |
| "")) /* Empty */)}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "dumpmanager_1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryShortTypeCrashdumpSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/3"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(1000000)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", DbusVariantType(std::string("Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("3")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_dir4"; |
| std::string hostDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(hostDir); |
| { |
| std::ofstream ofs(hostDir + "3", std::ios::binary); |
| ofs << "dummy"; |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_system1_3", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Id"], "3"); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryMissingTimestampInternalError) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/1"), |
| DBusInteracesMap{{std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair("Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", DbusVariantType(std::string( |
| "valid_id")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "dumpmanager_1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::internal_server_error); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryNonCrashdumpTypeNotFound) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/5"), |
| DBusInteracesMap{ |
| {std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(100)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair("Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.CPER"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("5")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "dumpmanager_5"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryWithFilePayloadSuccess) { |
| std::string tempDirPath = "/tmp/test_dumpmanager_dir3"; |
| std::string hostDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(hostDir); |
| { |
| std::ofstream ofs(hostDir + "10", std::ios::binary); |
| ofs << "CRASHDUMP_TEST_PAYLOAD"; |
| } |
| |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/10"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(500000)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("10")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_system1_10", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json expectedJson = nlohmann::json::parse(R"({ |
| "@odata.id": "/redfish/v1/Systems/system1/LogServices/Crashdump/Entries/dumpmanager_system1_10", |
| "@odata.type": "#LogEntry.v1_11_0.LogEntry", |
| "Created": "1970-01-01T00:00:00.500000+00:00", |
| "DiagnosticData": "Q1JBU0hEVU1QX1RFU1RfUEFZTE9BRA==", |
| "DiagnosticDataType": "CPER", |
| "EntryType": "Oem", |
| "Id": "10", |
| "Name": "Host Crashdump Entry" |
| })"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue, expectedJson); |
| } |
| |
| TEST_F(SnapshotFixture, |
| GetCrashdumpEntryCollectionPrimaryCrashdumpSuccessAndEmptyPath) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| MapperGetSubTreePathsResponse crashdumpPaths = { |
| "/", // Empty filename -> skipped |
| "/com/intel/crashdump/log1" // Valid primary crashdump |
| }; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, CreateValueType(crashdumpPaths)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/2"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("2")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, CreateMockFaultLogCPEREntry()) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_dir"; |
| std::string hostDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(hostDir); |
| { |
| std::ofstream ofs(hostDir + "2", std::ios::binary); |
| ofs << "dummy"; |
| } |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system1", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members@odata.count"], 2); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryCollectionPrimaryCrashdumpDbusError) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, |
| CreateErrorValueType(MapperGetSubTreePathsResponse{}, |
| boost::system::errc::make_error_code( |
| boost::system::errc::io_error))) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/2"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair("xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(0)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("2")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, CreateMockFaultLogCPEREntry()) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_dir2"; |
| std::string hostDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(hostDir); |
| { |
| std::ofstream ofs(hostDir + "2", std::ios::binary); |
| ofs << "dummy"; |
| } |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system1", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryCollectionDumpManagerDbusError) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| MapperGetSubTreePathsResponse emptyCrashdumpPaths = {}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, CreateValueType(emptyCrashdumpPaths)) |
| .ok()); |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, |
| CreateErrorValueType(ManagedObjectType{}, |
| boost::system::errc::make_error_code( |
| boost::system::errc::io_error))) |
| .ok()); |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members@odata.count"], 0); |
| } |
| |
| TEST_F( |
| SnapshotFixture, |
| GetCrashdumpEntryCollectionDumpManagerSkipNonMatchingPrefixAndEmptyFilename) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| MapperGetSubTreePathsResponse emptyCrashdumpPaths = {}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, CreateValueType(emptyCrashdumpPaths)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair(sdbusplus::message::object_path( |
| "/xyz/openbmc_project/other/entry/1"), |
| DBusInteracesMap{}), |
| std::make_pair(sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/"), |
| DBusInteracesMap{})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members@odata.count"], 0); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryCollectionInvalidSystemName) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "invalid_system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, |
| "invalid_system", "dumpmanager_1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryPropertyTypeMismatchInternalError) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/20"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{ |
| {std::make_pair("Elapsed", |
| DbusVariantType(std::string("invalid"))), |
| std::make_pair("OtherProp", |
| DbusVariantType(uint64_t(100)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair("Type", DbusVariantType(uint64_t(123))), |
| std::make_pair("PrimaryLogId", |
| DbusVariantType(uint64_t(456))), |
| std::make_pair("OtherProp", DbusVariantType(std::string( |
| "val")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "dumpmanager_20"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryPrettyNameSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/8"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(1000000)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", |
| DbusVariantType(std::string("8"))), |
| std::make_pair("PrettyName", |
| DbusVariantType(std::string( |
| "Component 1 Crashdump")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_pn"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| { |
| std::ofstream ofs(targetDir + "8", std::ios::binary); |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_8", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Name"], "Component 1 Crashdump"); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryMultiHostSystemAgnosticSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| // Entry at system-agnostic path /xyz/openbmc_project/dump/faultlog/entry/9 |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/9"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(2000000)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", |
| DbusVariantType(std::string("9"))), |
| std::make_pair("PrettyName", |
| DbusVariantType(std::string( |
| "Component 2 Crashdump")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_sa"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| { |
| std::ofstream ofs(targetDir + "9", std::ios::binary); |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_9", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Id"], "9"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Name"], "Component 2 Crashdump"); |
| } |
| |
| TEST_F(SnapshotFixture, |
| GetCrashdumpEntryCollectionMultiHostIncludesSystemAgnosticAndSpecific) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| const std::vector<std::string> crashInterfaces = {"com.intel.crashdump"}; |
| KeyType crashdumpKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| crashInterfaces); |
| MapperGetSubTreePathsResponse emptyCrashdumpPaths = {}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| crashdumpKey, CreateValueType(emptyCrashdumpPaths)) |
| .ok()); |
| |
| // Entry 1: System-specific for system1 |
| // (/xyz/openbmc_project/dump/faultlog/0/entry/1) Entry 2: System-agnostic |
| // (/xyz/openbmc_project/dump/faultlog/entry/2) |
| ManagedObjectType mockFaultLogEntries{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/1"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(100)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair( |
| "PrimaryLogId", |
| DbusVariantType(std::string("1")))}})}}), |
| std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/entry/2"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(200)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", |
| DbusVariantType(std::string("2"))), |
| std::make_pair( |
| "PrettyName", |
| DbusVariantType(std::string( |
| "Component Shared Crashdump")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntries))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_mh3"; |
| std::string targetDir = |
| tempDirPath + "/var/run/pldm/event/repo/host0/Crashdump/"; |
| std::filesystem::create_directories(targetDir); |
| { |
| std::ofstream ofs(targetDir + "1", std::ios::binary); |
| } |
| { |
| std::ofstream ofs(targetDir + "2", std::ios::binary); |
| } |
| |
| handleGetCrashdumpEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system1", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members@odata.count"], 2); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members"][0]["Id"], "1"); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["Members"][1]["Id"], "2"); |
| } |
| |
| TEST_F(SnapshotFixture, GetCrashdumpEntryLogDbusPropertyOverrideSuccess) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system1", |
| "/xyz/openbmc_project/inventory/system/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| ManagedObjectType mockFaultLogEntry{ |
| {std::make_pair( |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/dump/faultlog/0/entry/15"), |
| DBusInteracesMap{ |
| {std::make_pair( |
| "xyz.openbmc_project.Common.Progress", |
| DBusPropertiesMap{{std::make_pair( |
| "Status", DbusVariantType(std::string( |
| "xyz.openbmc_project.Common.Progress." |
| "OperationStatus.Completed")))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Time.EpochTime", |
| DBusPropertiesMap{{std::make_pair( |
| "Elapsed", DbusVariantType(uint64_t(3000000)))}}), |
| std::make_pair( |
| "xyz.openbmc_project.Dump.Entry.FaultLog", |
| DBusPropertiesMap{ |
| {std::make_pair( |
| "Type", |
| DbusVariantType(std::string( |
| "xyz.openbmc_project.Common." |
| "FaultLogType.FaultLogTypes.Crashdump"))), |
| std::make_pair("PrimaryLogId", |
| DbusVariantType(std::string("15"))), |
| std::make_pair( |
| "Log", |
| DbusVariantType(std::string( |
| "/custom/path/to/crashdump15.bin")))}})}})}, |
| }; |
| |
| KeyType dumpKey(ManagedType::kManagedObject, |
| "xyz.openbmc_project.Dump.Manager", |
| sdbusplus::message::object_path("/xyz/openbmc_project/dump")); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| dumpKey, managedStore::MockManagedStoreTest::CreateValueType( |
| std::move(mockFaultLogEntry))) |
| .ok()); |
| |
| std::string tempDirPath = "/tmp/test_dumpmanager_log_prop"; |
| std::string customFileDir = tempDirPath + "/custom/path/to/"; |
| std::filesystem::create_directories(customFileDir); |
| { |
| std::ofstream ofs(customFileDir + "crashdump15.bin", std::ios::binary); |
| ofs << "custom_log_property_content"; |
| } |
| |
| handleGetCrashdumpEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "dumpmanager_system1_15", tempDirPath); |
| RunIoUntilDone(); |
| |
| std::filesystem::remove_all(tempDirPath); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.jsonValue["DiagnosticData"], |
| "Y3VzdG9tX2xvZ19wcm9wZXJ0eV9jb250ZW50"); |
| } |
| |
| TEST_F(SnapshotFixture, PostCodesLogServiceGetSuccess_SingleHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| handleGetPostCodesLogService(app_, CreateRequest(), share_async_resp_, |
| "system"); |
| 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/PostCodes"); |
| EXPECT_EQ(json["@odata.type"], "#LogService.v1_1_0.LogService"); |
| EXPECT_EQ(json["Id"], "PostCodes"); |
| EXPECT_EQ(json["Name"], "POST Code Log Service"); |
| EXPECT_EQ(json["Description"], "POST Code Log Service"); |
| EXPECT_EQ(json["OverWritePolicy"], "WrapsWhenFull"); |
| EXPECT_EQ(json["Entries"]["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"); |
| EXPECT_EQ(json["Actions"]["#LogService.ClearLog"]["target"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/" |
| "LogService.ClearLog"); |
| |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); |
| handleGetPostCodesLogService(app_, CreateRequest(), share_async_resp_, |
| "system1"); |
| RunIoUntilDone(); |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); |
| handleGetPostCodesLogService(app_, CreateRequest(), share_async_resp_, |
| "invalid"); |
| RunIoUntilDone(); |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| |
| TEST_F(SnapshotFixture_Platform23, PostCodesLogServiceGetSuccess_MultiHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockMultiSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/board/platform23/system1", |
| "/xyz/openbmc_project/inventory/system/board/platform23/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockMultiSystemResponse)) |
| .ok()); |
| |
| handleGetPostCodesLogService(app_, CreateRequest(), share_async_resp_, |
| "system1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& json1 = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json1["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/PostCodes"); |
| EXPECT_EQ(json1["@odata.type"], "#LogService.v1_1_0.LogService"); |
| EXPECT_EQ(json1["Id"], "PostCodes"); |
| EXPECT_EQ(json1["Name"], "POST Code Log Service"); |
| EXPECT_EQ(json1["Entries"]["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/PostCodes/Entries"); |
| EXPECT_EQ(json1["Actions"]["#LogService.ClearLog"]["target"], |
| "/redfish/v1/Systems/system1/LogServices/PostCodes/Actions/" |
| "LogService.ClearLog"); |
| |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); |
| handleGetPostCodesLogService(app_, CreateRequest(), share_async_resp_, |
| "system2"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& json2 = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(json2["@odata.id"], |
| "/redfish/v1/Systems/system2/LogServices/PostCodes"); |
| EXPECT_EQ(json2["Entries"]["@odata.id"], |
| "/redfish/v1/Systems/system2/LogServices/PostCodes/Entries"); |
| |
| for (const char* invalidSystem : |
| {"system0", "system3", "system1abc", "system1/abc", "system", |
| "system99999999999999999999999999", "foo"}) { |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); |
| handleGetPostCodesLogService(app_, CreateRequest(), share_async_resp_, |
| invalidSystem); |
| RunIoUntilDone(); |
| EXPECT_EQ(share_async_resp_->res.result(), |
| boost::beast::http::status::not_found); |
| } |
| } |
| |
| TEST_F(SnapshotFixture, PostCodesClearPostSuccess_SingleHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll")) |
| .WillOnce([](const auto&, auto&& callback, const auto&, const auto&, |
| const auto&, |
| const auto&) { callback(boost::system::error_code()); }); |
| |
| handlePostPostCodesClear(app_, CreateRequest(), share_async_resp_, "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_TRUE( |
| share_async_resp_->res.jsonValue.contains("@Message.ExtendedInfo")); |
| } |
| |
| TEST_F(SnapshotFixture_Platform23, PostCodesClearPostSuccess_MultiHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockMultiSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/board/platform23/system1", |
| "/xyz/openbmc_project/inventory/system/board/platform23/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockMultiSystemResponse)) |
| .ok()); |
| |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode1", |
| "/xyz/openbmc_project/State/Boot/PostCode1", |
| "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll")) |
| .WillOnce([](const auto&, auto&& callback, const auto&, const auto&, |
| const auto&, |
| const auto&) { callback(boost::system::error_code()); }); |
| |
| handlePostPostCodesClear(app_, CreateRequest(), share_async_resp_, "system1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_TRUE( |
| share_async_resp_->res.jsonValue.contains("@Message.ExtendedInfo")); |
| } |
| |
| TEST_F(SnapshotFixture, PostCodesEntryCollectionGetSuccess_SingleHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| KeyType bootCountKey( |
| ManagedType::kManagedProperty, "xyz.openbmc_project.State.Boot.PostCode0", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/State/Boot/PostCode0"), |
| "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount"); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| bootCountKey, CreateValueType(dbus::utility::DbusVariantType( |
| static_cast<uint16_t>(1)))) |
| .ok()); |
| |
| boost::container::flat_map<uint64_t, |
| std::tuple<uint64_t, std::vector<uint8_t>>> |
| postcodes = { |
| {1000000ULL, {0xb000a915ULL, {0x15, 0xa9, 0x00, 0xb0}}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| handleGetPostCodesEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system"); |
| 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/PostCodes/Entries"); |
| EXPECT_EQ(json["@odata.type"], "#LogEntryCollection.LogEntryCollection"); |
| EXPECT_EQ(json["Members@odata.count"], 1); |
| ASSERT_EQ(json["Members"].size(), 1); |
| EXPECT_EQ(json["Members"][0]["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/B1-1"); |
| EXPECT_EQ(json["Members"][0]["Id"], "B1-1"); |
| EXPECT_EQ(json["Members"][0]["MessageArgs"], |
| std::vector<std::string>({"1", "0.0000", "0xb000a915"})); |
| } |
| |
| TEST_F(SnapshotFixture, PostCodesEntryCollectionGetSuccess_Pagination) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| KeyType bootCountKey( |
| ManagedType::kManagedProperty, "xyz.openbmc_project.State.Boot.PostCode0", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/State/Boot/PostCode0"), |
| "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount"); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| bootCountKey, CreateValueType(dbus::utility::DbusVariantType( |
| static_cast<uint16_t>(1)))) |
| .ok()); |
| |
| boost::container::flat_map<uint64_t, |
| std::tuple<uint64_t, std::vector<uint8_t>>> |
| postcodes = { |
| {1000000ULL, {0xb000a915ULL, {0x15, 0xa9, 0x00, 0xb0}}}, |
| {2000000ULL, {0xb000a916ULL, {0x16, 0xa9, 0x00, 0xb0}}}, |
| {3000000ULL, {0xb000a917ULL, {0x17, 0xa9, 0x00, 0xb0}}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| crow::Request req = CreateRequest(); |
| req.set_method(boost::beast::http::verb::get); |
| req.target( |
| "/redfish/v1/Systems/system/LogServices/PostCodes/" |
| "Entries?$skip=1&$top=1"); |
| handleGetPostCodesEntryCollection(app_, req, share_async_resp_, "system"); |
| 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/PostCodes/Entries"); |
| EXPECT_EQ(json["Members@odata.count"], 3); |
| ASSERT_EQ(json["Members"].size(), 1); |
| EXPECT_EQ(json["Members"][0]["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/B1-2"); |
| EXPECT_EQ(json["Members@odata.nextLink"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=2"); |
| |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| crow::Request reqSkipAll = CreateRequest(); |
| reqSkipAll.set_method(boost::beast::http::verb::get); |
| reqSkipAll.target( |
| "/redfish/v1/Systems/system/LogServices/PostCodes/" |
| "Entries?$skip=10&$top=5"); |
| handleGetPostCodesEntryCollection(app_, reqSkipAll, share_async_resp_, |
| "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& jsonSkipAll = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(jsonSkipAll["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"); |
| EXPECT_EQ(jsonSkipAll["Members@odata.count"], 3); |
| EXPECT_TRUE(jsonSkipAll["Members"].empty()); |
| EXPECT_FALSE(jsonSkipAll.contains("Members@odata.nextLink")); |
| |
| // Test multi-boot pagination where (top + skip) <= entryCount for later boots |
| KeyType multiBootKey( |
| ManagedType::kManagedProperty, "xyz.openbmc_project.State.Boot.PostCode0", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/State/Boot/PostCode0"), |
| "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount"); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| multiBootKey, CreateValueType(dbus::utility::DbusVariantType( |
| static_cast<uint16_t>(2)))) |
| .ok()); |
| |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| boost::container::flat_map<uint64_t, |
| std::tuple<uint64_t, std::vector<uint8_t>>> |
| postcodesBoot2 = { |
| {4000000ULL, {0xb000a918ULL, {0x18, 0xa9, 0x00, 0xb0}}}, |
| {5000000ULL, {0xb000a919ULL, {0x19, 0xa9, 0x00, 0xb0}}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(2))) |
| .WillOnce([postcodesBoot2](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, |
| uint16_t) { |
| callback(boost::system::error_code(), postcodesBoot2); |
| }); |
| |
| crow::Request reqMultiBoot = CreateRequest(); |
| reqMultiBoot.set_method(boost::beast::http::verb::get); |
| reqMultiBoot.target( |
| "/redfish/v1/Systems/system/LogServices/PostCodes/" |
| "Entries?$top=1&$skip=0"); |
| handleGetPostCodesEntryCollection(app_, reqMultiBoot, share_async_resp_, |
| "system"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| nlohmann::json& jsonMultiBoot = share_async_resp_->res.jsonValue; |
| EXPECT_EQ(jsonMultiBoot["@odata.id"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"); |
| EXPECT_EQ(jsonMultiBoot["Members@odata.count"], 5); |
| ASSERT_EQ(jsonMultiBoot["Members"].size(), 1); |
| EXPECT_EQ(jsonMultiBoot["Members"][0]["Id"], "B1-1"); |
| EXPECT_EQ(jsonMultiBoot["Members@odata.nextLink"], |
| "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=1"); |
| } |
| |
| TEST_F(SnapshotFixture_Platform23, |
| PostCodesEntryCollectionGetSuccess_MultiHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockMultiSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/board/platform23/system1", |
| "/xyz/openbmc_project/inventory/system/board/platform23/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockMultiSystemResponse)) |
| .ok()); |
| |
| KeyType bootCountKey( |
| ManagedType::kManagedProperty, "xyz.openbmc_project.State.Boot.PostCode1", |
| sdbusplus::message::object_path( |
| "/xyz/openbmc_project/State/Boot/PostCode1"), |
| "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount"); |
| ASSERT_TRUE( |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| bootCountKey, CreateValueType(dbus::utility::DbusVariantType( |
| static_cast<uint16_t>(1)))) |
| .ok()); |
| |
| boost::container::flat_map<uint64_t, |
| std::tuple<uint64_t, std::vector<uint8_t>>> |
| postcodes = { |
| {1000000ULL, {0xb000a915ULL, {0x15, 0xa9, 0x00, 0xb0}}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode1", |
| "/xyz/openbmc_project/State/Boot/PostCode1", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| handleGetPostCodesEntryCollection(app_, CreateRequest(), share_async_resp_, |
| "system1"); |
| 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/system1/LogServices/PostCodes/Entries"); |
| EXPECT_EQ(json["Members@odata.count"], 1); |
| ASSERT_EQ(json["Members"].size(), 1); |
| EXPECT_EQ(json["Members"][0]["@odata.id"], |
| "/redfish/v1/Systems/system1/LogServices/PostCodes/Entries/B1-1"); |
| } |
| |
| TEST_F(SnapshotFixture, PostCodesEntryGetSuccess_SingleHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| boost::container::flat_map<uint64_t, |
| std::tuple<uint64_t, std::vector<uint8_t>>> |
| postcodes = { |
| {1000000ULL, {0xb000a915ULL, {0x15, 0xa9, 0x00, 0xb0}}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| handleGetPostCodesEntry(app_, CreateRequest(), share_async_resp_, "system", |
| "B1-1"); |
| 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/PostCodes/Entries/B1-1"); |
| EXPECT_EQ(json["Id"], "B1-1"); |
| EXPECT_EQ(json["MessageArgs"], |
| std::vector<std::string>({"1", "0.0000", "0xb000a915"})); |
| } |
| |
| TEST_F(SnapshotFixture_Platform23, PostCodesEntryGetSuccess_MultiHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockMultiSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/board/platform23/system1", |
| "/xyz/openbmc_project/inventory/system/board/platform23/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockMultiSystemResponse)) |
| .ok()); |
| |
| boost::container::flat_map<uint64_t, |
| std::tuple<uint64_t, std::vector<uint8_t>>> |
| postcodes = { |
| {1000000ULL, {0xb000a915ULL, {0x15, 0xa9, 0x00, 0xb0}}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const boost::container::flat_map< |
| uint64_t, managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode1", |
| "/xyz/openbmc_project/State/Boot/PostCode1", |
| "xyz.openbmc_project.State.Boot.PostCode", |
| "GetPostCodesWithTimeStamp", static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| handleGetPostCodesEntry(app_, CreateRequest(), share_async_resp_, "system1", |
| "B1-1"); |
| 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/system1/LogServices/PostCodes/Entries/B1-1"); |
| EXPECT_EQ(json["Id"], "B1-1"); |
| } |
| |
| TEST_F(SnapshotFixture, PostCodesEntryAdditionalDataGetSuccess_SingleHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/system"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockSystemResponse)) |
| .ok()); |
| |
| std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postcodes = { |
| {1000000ULL, {'T', 'E', 'S', 'T'}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const std::vector<managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode0", |
| "/xyz/openbmc_project/State/Boot/PostCode0", |
| "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", |
| static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| handleGetPostCodesEntryAdditionalData(app_, CreateRequest(), |
| share_async_resp_, "system", "B1-1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.getHeaderValue("Content-Type"), |
| "application/octet-stream"); |
| EXPECT_EQ(share_async_resp_->res.getHeaderValue("Content-Transfer-Encoding"), |
| "Base64"); |
| std::string decoded1; |
| EXPECT_TRUE( |
| crow::utility::base64Decode(share_async_resp_->res.body(), decoded1)); |
| EXPECT_EQ(decoded1, "TEST"); |
| } |
| |
| TEST_F(SnapshotFixture_Platform23, |
| PostCodesEntryAdditionalDataGetSuccess_MultiHost) { |
| KeyType systemKey(ManagedType::kManagedSubtreePaths, "/", 0, |
| {kSystemInterfaces.begin(), kSystemInterfaces.end()}); |
| MapperGetSubTreePathsResponse mockMultiSystemResponse = { |
| "/xyz/openbmc_project/inventory/system/board/platform23/system1", |
| "/xyz/openbmc_project/inventory/system/board/platform23/system2"}; |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()) |
| ->upsertMockObjectIntoManagedStore( |
| systemKey, CreateValueType(mockMultiSystemResponse)) |
| .ok()); |
| |
| std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postcodes = { |
| {1000000ULL, {'T', 'E', 'S', 'T'}}, |
| }; |
| EXPECT_CALL( |
| *dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( |
| managedStore::GetManagedObjectStore()), |
| PostDbusCallToIoContextThreadSafe( |
| _, |
| An<absl::AnyInvocable<void( |
| const boost::system::error_code&, |
| const std::vector<managedStore::MockSerializedManagedObjectStore:: |
| PostCodeEntry>&)>&&>(), |
| "xyz.openbmc_project.State.Boot.PostCode1", |
| "/xyz/openbmc_project/State/Boot/PostCode1", |
| "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", |
| static_cast<uint16_t>(1))) |
| .WillOnce([postcodes](const auto&, auto&& callback, const auto&, |
| const auto&, const auto&, const auto&, uint16_t) { |
| callback(boost::system::error_code(), postcodes); |
| }); |
| |
| handleGetPostCodesEntryAdditionalData(app_, CreateRequest(), |
| share_async_resp_, "system1", "B1-1"); |
| RunIoUntilDone(); |
| |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); |
| EXPECT_EQ(share_async_resp_->res.getHeaderValue("Content-Type"), |
| "application/octet-stream"); |
| EXPECT_EQ(share_async_resp_->res.getHeaderValue("Content-Transfer-Encoding"), |
| "Base64"); |
| std::string decoded2; |
| EXPECT_TRUE( |
| crow::utility::base64Decode(share_async_resp_->res.body(), decoded2)); |
| EXPECT_EQ(decoded2, "TEST"); |
| } |
| |
| } // namespace |
| } // namespace redfish |