#include "rde/external_storer_file.hpp" #include #include #include #include #include #include namespace bios_bmc_smm_error_logger { namespace rde { using ::testing::_; using ::testing::DoAll; using ::testing::Return; using ::testing::SaveArg; using ::testing::StrEq; class MockFileWriter : public FileHandlerInterface { public: MOCK_METHOD(bool, createFolder, (const std::string& path), (const, override)); MOCK_METHOD(bool, createFile, (const std::string& path, const nlohmann::json& jsonPdr), (const, override)); }; class ExternalStorerFileTest : public ::testing::Test { public: ExternalStorerFileTest() : bus(sdbusplus::get_mocked_new(&sdbusMock)), mockFileWriter(std::make_unique()) { mockFileWriterPtr = dynamic_cast(mockFileWriter.get()); EXPECT_CALL( sdbusMock, sd_bus_add_object_manager( nullptr, _, StrEq( "/xyz/openbmc_project/external_storer/bios_bmc_smm_error_logger/CPER"))) .WillOnce(Return(0)); exStorer = std::make_unique( bus, rootPath, std::move(mockFileWriter)); } protected: sdbusplus::SdBusMock sdbusMock; sdbusplus::bus_t bus; std::unique_ptr mockFileWriter; std::unique_ptr exStorer; MockFileWriter* mockFileWriterPtr; const std::string rootPath = "/some/path"; }; TEST_F(ExternalStorerFileTest, InvalidJsonTest) { // Try an invalid JSON. std::string jsonStr = "Invalid JSON"; EXPECT_THAT(exStorer->publishJson(jsonStr), false); } TEST_F(ExternalStorerFileTest, NoOdataTypeFailureTest) { // Try a JSON without @odata.type. std::string jsonStr = R"( { "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics", "Id":"Metrics" } )"; EXPECT_THAT(exStorer->publishJson(jsonStr), false); } TEST_F(ExternalStorerFileTest, LogServiceNoOdataIdTest) { // Try a LogService without @odata.id. std::string jsonStr = R"( { "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C" } )"; EXPECT_THAT(exStorer->publishJson(jsonStr), false); } TEST_F(ExternalStorerFileTest, LogServiceNoIdTest) { // Try a LogService without Id. std::string jsonStr = R"( { "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C", "@odata.type": "#LogService.v1_1_0.LogService" } )"; EXPECT_THAT(exStorer->publishJson(jsonStr), false); } TEST_F(ExternalStorerFileTest, LogServiceTest) { // A valid LogService test. std::string jsonStr = R"( { "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C", "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C" } )"; std::string exServiceFolder = "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C"; std::string exEntriesFolder = "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries"; nlohmann::json exEntriesJson = "{}"_json; nlohmann::json exServiceJson = nlohmann::json::parse(jsonStr); EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson)) .WillOnce(Return(true)); EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson)) .WillOnce(Return(true)); EXPECT_THAT(exStorer->publishJson(jsonStr), true); } TEST_F(ExternalStorerFileTest, LogEntryWithoutLogServiceTest) { // Try a LogEntry without sending a LogService first. std::string jsonLogEntry = R"( { "@odata.type": "#LogEntry.v1_13_0.LogEntry" } )"; EXPECT_THAT(exStorer->publishJson(jsonLogEntry), false); } TEST_F(ExternalStorerFileTest, LogEntryTest) { // Before sending a LogEntry, first we need to push a LogService. std::string jsonLogSerivce = R"( { "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C", "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C" } )"; std::string exServiceFolder = "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C"; std::string exEntriesFolder = "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries"; nlohmann::json exEntriesJson = "{}"_json; nlohmann::json exServiceJson = nlohmann::json::parse(jsonLogSerivce); EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson)) .WillOnce(Return(true)); EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson)) .WillOnce(Return(true)); EXPECT_THAT(exStorer->publishJson(jsonLogSerivce), true); // Now send a LogEntry std::string jsonLogEntry = R"( { "@odata.id": "/some/odata/id", "@odata.type": "#LogEntry.v1_13_0.LogEntry" } )"; nlohmann::json logEntryOut; EXPECT_CALL(*mockFileWriterPtr, createFile(_, _)) .WillOnce(DoAll(SaveArg<1>(&logEntryOut), Return(true))); constexpr const char* dbusPath = "/xyz/openbmc_project/external_storer/bios_bmc_smm_error_logger/CPER/entry0"; constexpr const char* dbusInterface = "xyz.openbmc_project.Common.FilePath"; EXPECT_CALL(sdbusMock, sd_bus_add_object_vtable(nullptr, _, StrEq(dbusPath), StrEq(dbusInterface), _, _)) .WillOnce(Return(0)); EXPECT_CALL(sdbusMock, sd_bus_emit_interfaces_added_strv(nullptr, StrEq(dbusPath), _)) .WillOnce(Return(0)); EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true); EXPECT_NE(logEntryOut["Id"], nullptr); EXPECT_EQ(logEntryOut["@odata.id"], nullptr); EXPECT_CALL(sdbusMock, sd_bus_emit_interfaces_removed_strv( nullptr, StrEq(dbusPath), _)) .WillOnce(Return(0)); } TEST_F(ExternalStorerFileTest, OtherSchemaNoOdataIdTest) { // Try a another PDRs without @odata.id. std::string jsonStr = R"( { "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics", "Id":"Metrics" } )"; EXPECT_THAT(exStorer->publishJson(jsonStr), false); } TEST_F(ExternalStorerFileTest, OtherSchemaTypeTest) { // A valid MemoryMetrics PDR. std::string jsonStr = R"( { "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics", "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics", "Id": "Metrics" } )"; std::string exFolder = "/some/path/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics"; nlohmann::json exJson = nlohmann::json::parse(jsonStr); EXPECT_CALL(*mockFileWriterPtr, createFile(exFolder, exJson)) .WillOnce(Return(true)); EXPECT_THAT(exStorer->publishJson(jsonStr), true); } } // namespace rde } // namespace bios_bmc_smm_error_logger