137bc0df1Skasunath #include "rde/external_storer_file.hpp"
237bc0df1Skasunath 
3a3b64fb6Skasunath #include <sdbusplus/bus.hpp>
4a3b64fb6Skasunath #include <sdbusplus/test/sdbus_mock.hpp>
5a3b64fb6Skasunath 
637bc0df1Skasunath #include <string_view>
737bc0df1Skasunath 
837bc0df1Skasunath #include <gmock/gmock-matchers.h>
937bc0df1Skasunath #include <gmock/gmock.h>
1037bc0df1Skasunath #include <gtest/gtest.h>
1137bc0df1Skasunath 
1237bc0df1Skasunath namespace bios_bmc_smm_error_logger
1337bc0df1Skasunath {
1437bc0df1Skasunath namespace rde
1537bc0df1Skasunath {
1637bc0df1Skasunath 
1737bc0df1Skasunath using ::testing::_;
1837bc0df1Skasunath using ::testing::DoAll;
1937bc0df1Skasunath using ::testing::Return;
2037bc0df1Skasunath using ::testing::SaveArg;
21a3b64fb6Skasunath using ::testing::StrEq;
2237bc0df1Skasunath 
2337bc0df1Skasunath class MockFileWriter : public FileHandlerInterface
2437bc0df1Skasunath {
2537bc0df1Skasunath   public:
2637bc0df1Skasunath     MOCK_METHOD(bool, createFolder, (const std::string& path),
2737bc0df1Skasunath                 (const, override));
2837bc0df1Skasunath     MOCK_METHOD(bool, createFile,
2937bc0df1Skasunath                 (const std::string& path, const nlohmann::json& jsonPdr),
3037bc0df1Skasunath                 (const, override));
3137bc0df1Skasunath };
3237bc0df1Skasunath 
3337bc0df1Skasunath class ExternalStorerFileTest : public ::testing::Test
3437bc0df1Skasunath {
3537bc0df1Skasunath   public:
ExternalStorerFileTest()3637bc0df1Skasunath     ExternalStorerFileTest() :
37a3b64fb6Skasunath         bus(sdbusplus::get_mocked_new(&sdbusMock)),
3837bc0df1Skasunath         mockFileWriter(std::make_unique<MockFileWriter>())
3937bc0df1Skasunath     {
4037bc0df1Skasunath         mockFileWriterPtr = dynamic_cast<MockFileWriter*>(mockFileWriter.get());
41a3b64fb6Skasunath 
42a3b64fb6Skasunath         EXPECT_CALL(
43a3b64fb6Skasunath             sdbusMock,
44a3b64fb6Skasunath             sd_bus_add_object_manager(
45a3b64fb6Skasunath                 nullptr, _,
46a3b64fb6Skasunath                 StrEq(
47a3b64fb6Skasunath                     "/xyz/openbmc_project/external_storer/bios_bmc_smm_error_logger/CPER")))
48a3b64fb6Skasunath             .WillOnce(Return(0));
49a3b64fb6Skasunath 
5037bc0df1Skasunath         exStorer = std::make_unique<ExternalStorerFileInterface>(
51a3b64fb6Skasunath             bus, rootPath, std::move(mockFileWriter));
5237bc0df1Skasunath     }
5337bc0df1Skasunath 
5437bc0df1Skasunath   protected:
55a3b64fb6Skasunath     sdbusplus::SdBusMock sdbusMock;
56*bea36e22SPatrick Williams     sdbusplus::bus_t bus;
5737bc0df1Skasunath     std::unique_ptr<FileHandlerInterface> mockFileWriter;
5837bc0df1Skasunath     std::unique_ptr<ExternalStorerFileInterface> exStorer;
5937bc0df1Skasunath     MockFileWriter* mockFileWriterPtr;
6037bc0df1Skasunath     const std::string rootPath = "/some/path";
6137bc0df1Skasunath };
6237bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,InvalidJsonTest)6337bc0df1Skasunath TEST_F(ExternalStorerFileTest, InvalidJsonTest)
6437bc0df1Skasunath {
6537bc0df1Skasunath     // Try an invalid JSON.
6637bc0df1Skasunath     std::string jsonStr = "Invalid JSON";
6737bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
6837bc0df1Skasunath }
6937bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,NoOdataTypeFailureTest)7037bc0df1Skasunath TEST_F(ExternalStorerFileTest, NoOdataTypeFailureTest)
7137bc0df1Skasunath {
7237bc0df1Skasunath     // Try a JSON without @odata.type.
7337bc0df1Skasunath     std::string jsonStr = R"(
7437bc0df1Skasunath       {
7537bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
7637bc0df1Skasunath         "Id":"Metrics"
7737bc0df1Skasunath       }
7837bc0df1Skasunath     )";
7937bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
8037bc0df1Skasunath }
8137bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogServiceNoOdataIdTest)8237bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogServiceNoOdataIdTest)
8337bc0df1Skasunath {
8437bc0df1Skasunath     // Try a LogService without @odata.id.
8537bc0df1Skasunath     std::string jsonStr = R"(
8637bc0df1Skasunath       {
8737bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
8837bc0df1Skasunath       }
8937bc0df1Skasunath     )";
9037bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
9137bc0df1Skasunath }
9237bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogServiceNoIdTest)9337bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogServiceNoIdTest)
9437bc0df1Skasunath {
9537bc0df1Skasunath     // Try a LogService without Id.
9637bc0df1Skasunath     std::string jsonStr = R"(
9737bc0df1Skasunath       {
9837bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
9937bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService"
10037bc0df1Skasunath       }
10137bc0df1Skasunath     )";
10237bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
10337bc0df1Skasunath }
10437bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogServiceTest)10537bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogServiceTest)
10637bc0df1Skasunath {
10737bc0df1Skasunath     // A valid LogService test.
10837bc0df1Skasunath     std::string jsonStr = R"(
10937bc0df1Skasunath       {
11037bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
11137bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
11237bc0df1Skasunath         }
11337bc0df1Skasunath       )";
11437bc0df1Skasunath     std::string exServiceFolder =
11537bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
11637bc0df1Skasunath     std::string exEntriesFolder =
11737bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
11837bc0df1Skasunath     nlohmann::json exEntriesJson = "{}"_json;
11937bc0df1Skasunath     nlohmann::json exServiceJson = nlohmann::json::parse(jsonStr);
12037bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
12137bc0df1Skasunath         .WillOnce(Return(true));
12237bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
12337bc0df1Skasunath         .WillOnce(Return(true));
12437bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), true);
12537bc0df1Skasunath }
12637bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogEntryWithoutLogServiceTest)12737bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogEntryWithoutLogServiceTest)
12837bc0df1Skasunath {
12937bc0df1Skasunath     // Try a LogEntry without sending a LogService first.
13037bc0df1Skasunath     std::string jsonLogEntry = R"(
13137bc0df1Skasunath       {
13237bc0df1Skasunath         "@odata.type": "#LogEntry.v1_13_0.LogEntry"
13337bc0df1Skasunath       }
13437bc0df1Skasunath     )";
13537bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), false);
13637bc0df1Skasunath }
13737bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogEntryTest)13837bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogEntryTest)
13937bc0df1Skasunath {
14037bc0df1Skasunath     // Before sending a LogEntry, first we need to push a LogService.
14137bc0df1Skasunath     std::string jsonLogSerivce = R"(
14237bc0df1Skasunath       {
14337bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
14437bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
14537bc0df1Skasunath       }
14637bc0df1Skasunath     )";
14737bc0df1Skasunath     std::string exServiceFolder =
14837bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
14937bc0df1Skasunath     std::string exEntriesFolder =
15037bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
15137bc0df1Skasunath     nlohmann::json exEntriesJson = "{}"_json;
15237bc0df1Skasunath     nlohmann::json exServiceJson = nlohmann::json::parse(jsonLogSerivce);
15337bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
15437bc0df1Skasunath         .WillOnce(Return(true));
15537bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
15637bc0df1Skasunath         .WillOnce(Return(true));
15737bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonLogSerivce), true);
15837bc0df1Skasunath 
15937bc0df1Skasunath     // Now send a LogEntry
16037bc0df1Skasunath     std::string jsonLogEntry = R"(
16137bc0df1Skasunath       {
16237bc0df1Skasunath         "@odata.id": "/some/odata/id",
16337bc0df1Skasunath         "@odata.type": "#LogEntry.v1_13_0.LogEntry"
16437bc0df1Skasunath       }
16537bc0df1Skasunath     )";
166a3b64fb6Skasunath 
16737bc0df1Skasunath     nlohmann::json logEntryOut;
16837bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
16937bc0df1Skasunath         .WillOnce(DoAll(SaveArg<1>(&logEntryOut), Return(true)));
170a3b64fb6Skasunath 
171a3b64fb6Skasunath     constexpr const char* dbusPath =
172a3b64fb6Skasunath         "/xyz/openbmc_project/external_storer/bios_bmc_smm_error_logger/CPER/entry0";
173a3b64fb6Skasunath     constexpr const char* dbusInterface = "xyz.openbmc_project.Common.FilePath";
174a3b64fb6Skasunath 
175a3b64fb6Skasunath     EXPECT_CALL(sdbusMock, sd_bus_add_object_vtable(nullptr, _, StrEq(dbusPath),
176a3b64fb6Skasunath                                                     StrEq(dbusInterface), _, _))
177a3b64fb6Skasunath         .WillOnce(Return(0));
178a3b64fb6Skasunath     EXPECT_CALL(sdbusMock,
179a3b64fb6Skasunath                 sd_bus_emit_interfaces_added_strv(nullptr, StrEq(dbusPath), _))
180a3b64fb6Skasunath         .WillOnce(Return(0));
181a3b64fb6Skasunath 
18237bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
18337bc0df1Skasunath     EXPECT_NE(logEntryOut["Id"], nullptr);
18437bc0df1Skasunath     EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
185a3b64fb6Skasunath 
186a3b64fb6Skasunath     EXPECT_CALL(sdbusMock, sd_bus_emit_interfaces_removed_strv(
187a3b64fb6Skasunath                                nullptr, StrEq(dbusPath), _))
188a3b64fb6Skasunath         .WillOnce(Return(0));
18937bc0df1Skasunath }
19037bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,OtherSchemaNoOdataIdTest)19137bc0df1Skasunath TEST_F(ExternalStorerFileTest, OtherSchemaNoOdataIdTest)
19237bc0df1Skasunath {
19337bc0df1Skasunath     // Try a another PDRs without @odata.id.
19437bc0df1Skasunath     std::string jsonStr = R"(
19537bc0df1Skasunath       {
19637bc0df1Skasunath         "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
19737bc0df1Skasunath         "Id":"Metrics"
19837bc0df1Skasunath       }
19937bc0df1Skasunath     )";
20037bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
20137bc0df1Skasunath }
20237bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,OtherSchemaTypeTest)20337bc0df1Skasunath TEST_F(ExternalStorerFileTest, OtherSchemaTypeTest)
20437bc0df1Skasunath {
20537bc0df1Skasunath     // A valid MemoryMetrics PDR.
20637bc0df1Skasunath     std::string jsonStr = R"(
20737bc0df1Skasunath       {
20837bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
20937bc0df1Skasunath         "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
21037bc0df1Skasunath         "Id": "Metrics"
21137bc0df1Skasunath       }
21237bc0df1Skasunath     )";
21337bc0df1Skasunath     std::string exFolder =
21437bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics";
21537bc0df1Skasunath     nlohmann::json exJson = nlohmann::json::parse(jsonStr);
21637bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exFolder, exJson))
21737bc0df1Skasunath         .WillOnce(Return(true));
21837bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), true);
21937bc0df1Skasunath }
22037bc0df1Skasunath 
22137bc0df1Skasunath } // namespace rde
22237bc0df1Skasunath } // namespace bios_bmc_smm_error_logger
223