xref: /openbmc/bios-bmc-smm-error-logger/test/external_storer_file_test.cpp (revision 41a58d4f8fc3debc1552d8a5e4e604b3268e2a8d)
137bc0df1Skasunath #include "rde/external_storer_file.hpp"
237bc0df1Skasunath 
33d0cd556Skasunath #include <boost/asio/io_context.hpp>
4a3b64fb6Skasunath 
537bc0df1Skasunath #include <string_view>
637bc0df1Skasunath 
737bc0df1Skasunath #include <gmock/gmock-matchers.h>
837bc0df1Skasunath #include <gmock/gmock.h>
937bc0df1Skasunath #include <gtest/gtest.h>
1037bc0df1Skasunath 
1137bc0df1Skasunath namespace bios_bmc_smm_error_logger
1237bc0df1Skasunath {
1337bc0df1Skasunath namespace rde
1437bc0df1Skasunath {
1537bc0df1Skasunath 
1637bc0df1Skasunath using ::testing::_;
1737bc0df1Skasunath using ::testing::DoAll;
18*41a58d4fSBrandon Kim using ::testing::InSequence;
1937bc0df1Skasunath using ::testing::Return;
2037bc0df1Skasunath using ::testing::SaveArg;
2137bc0df1Skasunath 
2237bc0df1Skasunath class MockFileWriter : public FileHandlerInterface
2337bc0df1Skasunath {
2437bc0df1Skasunath   public:
2537bc0df1Skasunath     MOCK_METHOD(bool, createFolder, (const std::string& path),
2637bc0df1Skasunath                 (const, override));
2737bc0df1Skasunath     MOCK_METHOD(bool, createFile,
2837bc0df1Skasunath                 (const std::string& path, const nlohmann::json& jsonPdr),
2937bc0df1Skasunath                 (const, override));
30*41a58d4fSBrandon Kim     MOCK_METHOD(bool, removeAll, (const std::string& path), (const, override));
3137bc0df1Skasunath };
3237bc0df1Skasunath 
3337bc0df1Skasunath class ExternalStorerFileTest : public ::testing::Test
3437bc0df1Skasunath {
3537bc0df1Skasunath   public:
ExternalStorerFileTest()3637bc0df1Skasunath     ExternalStorerFileTest() :
373d0cd556Skasunath         conn(std::make_shared<sdbusplus::asio::connection>(io)),
3837bc0df1Skasunath         mockFileWriter(std::make_unique<MockFileWriter>())
3937bc0df1Skasunath     {
4037bc0df1Skasunath         mockFileWriterPtr = dynamic_cast<MockFileWriter*>(mockFileWriter.get());
41*41a58d4fSBrandon Kim         // Set the queue of LogEntry to 1 saved entry and 2 non saved entry
4237bc0df1Skasunath         exStorer = std::make_unique<ExternalStorerFileInterface>(
43*41a58d4fSBrandon Kim             conn, rootPath, std::move(mockFileWriter), 1, 2);
4437bc0df1Skasunath     }
4537bc0df1Skasunath 
4637bc0df1Skasunath   protected:
473d0cd556Skasunath     boost::asio::io_context io;
483d0cd556Skasunath     std::shared_ptr<sdbusplus::asio::connection> conn;
493d0cd556Skasunath 
5037bc0df1Skasunath     std::unique_ptr<FileHandlerInterface> mockFileWriter;
5137bc0df1Skasunath     std::unique_ptr<ExternalStorerFileInterface> exStorer;
5237bc0df1Skasunath     MockFileWriter* mockFileWriterPtr;
5337bc0df1Skasunath     const std::string rootPath = "/some/path";
5437bc0df1Skasunath };
5537bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,InvalidJsonTest)5637bc0df1Skasunath TEST_F(ExternalStorerFileTest, InvalidJsonTest)
5737bc0df1Skasunath {
5837bc0df1Skasunath     // Try an invalid JSON.
5937bc0df1Skasunath     std::string jsonStr = "Invalid JSON";
6037bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
6137bc0df1Skasunath }
6237bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,NoOdataTypeFailureTest)6337bc0df1Skasunath TEST_F(ExternalStorerFileTest, NoOdataTypeFailureTest)
6437bc0df1Skasunath {
6537bc0df1Skasunath     // Try a JSON without @odata.type.
6637bc0df1Skasunath     std::string jsonStr = R"(
6737bc0df1Skasunath       {
6837bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
6937bc0df1Skasunath         "Id":"Metrics"
7037bc0df1Skasunath       }
7137bc0df1Skasunath     )";
7237bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
7337bc0df1Skasunath }
7437bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogServiceNoOdataIdTest)7537bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogServiceNoOdataIdTest)
7637bc0df1Skasunath {
7737bc0df1Skasunath     // Try a LogService without @odata.id.
7837bc0df1Skasunath     std::string jsonStr = R"(
7937bc0df1Skasunath       {
8037bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
8137bc0df1Skasunath       }
8237bc0df1Skasunath     )";
8337bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
8437bc0df1Skasunath }
8537bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogServiceNoIdTest)8637bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogServiceNoIdTest)
8737bc0df1Skasunath {
8837bc0df1Skasunath     // Try a LogService without Id.
8937bc0df1Skasunath     std::string jsonStr = R"(
9037bc0df1Skasunath       {
9137bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
9237bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService"
9337bc0df1Skasunath       }
9437bc0df1Skasunath     )";
9537bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
9637bc0df1Skasunath }
9737bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogServiceTest)9837bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogServiceTest)
9937bc0df1Skasunath {
10037bc0df1Skasunath     // A valid LogService test.
10137bc0df1Skasunath     std::string jsonStr = R"(
10237bc0df1Skasunath       {
10337bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
10437bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
10537bc0df1Skasunath         }
10637bc0df1Skasunath       )";
10737bc0df1Skasunath     std::string exServiceFolder =
10837bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
10937bc0df1Skasunath     std::string exEntriesFolder =
11037bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
11137bc0df1Skasunath     nlohmann::json exEntriesJson = "{}"_json;
11237bc0df1Skasunath     nlohmann::json exServiceJson = nlohmann::json::parse(jsonStr);
11337bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
11437bc0df1Skasunath         .WillOnce(Return(true));
11537bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
11637bc0df1Skasunath         .WillOnce(Return(true));
11737bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), true);
11837bc0df1Skasunath }
11937bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogEntryWithoutLogServiceTest)12037bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogEntryWithoutLogServiceTest)
12137bc0df1Skasunath {
12237bc0df1Skasunath     // Try a LogEntry without sending a LogService first.
12337bc0df1Skasunath     std::string jsonLogEntry = R"(
12437bc0df1Skasunath       {
12537bc0df1Skasunath         "@odata.type": "#LogEntry.v1_13_0.LogEntry"
12637bc0df1Skasunath       }
12737bc0df1Skasunath     )";
12837bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), false);
12937bc0df1Skasunath }
13037bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,LogEntryTest)13137bc0df1Skasunath TEST_F(ExternalStorerFileTest, LogEntryTest)
13237bc0df1Skasunath {
133*41a58d4fSBrandon Kim     InSequence s;
13437bc0df1Skasunath     // Before sending a LogEntry, first we need to push a LogService.
13537bc0df1Skasunath     std::string jsonLogSerivce = R"(
13637bc0df1Skasunath       {
13737bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
13837bc0df1Skasunath         "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
13937bc0df1Skasunath       }
14037bc0df1Skasunath     )";
14137bc0df1Skasunath     std::string exServiceFolder =
14237bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
14337bc0df1Skasunath     std::string exEntriesFolder =
14437bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
14537bc0df1Skasunath     nlohmann::json exEntriesJson = "{}"_json;
14637bc0df1Skasunath     nlohmann::json exServiceJson = nlohmann::json::parse(jsonLogSerivce);
14737bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
14837bc0df1Skasunath         .WillOnce(Return(true));
14937bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
15037bc0df1Skasunath         .WillOnce(Return(true));
15137bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonLogSerivce), true);
15237bc0df1Skasunath 
153*41a58d4fSBrandon Kim     // Now send a LogEntry#1, which will not be deleted
15437bc0df1Skasunath     std::string jsonLogEntry = R"(
15537bc0df1Skasunath       {
15637bc0df1Skasunath         "@odata.id": "/some/odata/id",
15737bc0df1Skasunath         "@odata.type": "#LogEntry.v1_13_0.LogEntry"
15837bc0df1Skasunath       }
15937bc0df1Skasunath     )";
16037bc0df1Skasunath     nlohmann::json logEntryOut;
161*41a58d4fSBrandon Kim     std::string logPath1;
16237bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
163*41a58d4fSBrandon Kim         .WillOnce(DoAll(SaveArg<0>(&logPath1), SaveArg<1>(&logEntryOut),
164*41a58d4fSBrandon Kim                         Return(true)));
16537bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
166*41a58d4fSBrandon Kim     EXPECT_FALSE(logPath1.empty());
167*41a58d4fSBrandon Kim     EXPECT_NE(logEntryOut["Id"], nullptr);
168*41a58d4fSBrandon Kim     EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
169*41a58d4fSBrandon Kim 
170*41a58d4fSBrandon Kim     // Now send a LogEntry#2, which will be the first to be deleted
171*41a58d4fSBrandon Kim     std::string logPath2;
172*41a58d4fSBrandon Kim     EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
173*41a58d4fSBrandon Kim         .WillOnce(DoAll(SaveArg<0>(&logPath2), SaveArg<1>(&logEntryOut),
174*41a58d4fSBrandon Kim                         Return(true)));
175*41a58d4fSBrandon Kim     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
176*41a58d4fSBrandon Kim     EXPECT_FALSE(logPath2.empty());
177*41a58d4fSBrandon Kim     EXPECT_NE(logEntryOut["Id"], nullptr);
178*41a58d4fSBrandon Kim     EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
179*41a58d4fSBrandon Kim 
180*41a58d4fSBrandon Kim     // Now send a LogEntry#3
181*41a58d4fSBrandon Kim     std::string logPath3;
182*41a58d4fSBrandon Kim     EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
183*41a58d4fSBrandon Kim         .WillOnce(DoAll(SaveArg<0>(&logPath3), SaveArg<1>(&logEntryOut),
184*41a58d4fSBrandon Kim                         Return(true)));
185*41a58d4fSBrandon Kim     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
186*41a58d4fSBrandon Kim     EXPECT_FALSE(logPath3.empty());
187*41a58d4fSBrandon Kim     EXPECT_NE(logEntryOut["Id"], nullptr);
188*41a58d4fSBrandon Kim     EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
189*41a58d4fSBrandon Kim 
190*41a58d4fSBrandon Kim     // Now send a LogEntry#4, we expect the LogEntry#2 to be deleted
191*41a58d4fSBrandon Kim     std::string logPath4;
192*41a58d4fSBrandon Kim     EXPECT_CALL(*mockFileWriterPtr, removeAll(logPath2)).WillOnce(Return(true));
193*41a58d4fSBrandon Kim     EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
194*41a58d4fSBrandon Kim         .WillOnce(DoAll(SaveArg<0>(&logPath4), SaveArg<1>(&logEntryOut),
195*41a58d4fSBrandon Kim                         Return(true)));
196*41a58d4fSBrandon Kim     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
197*41a58d4fSBrandon Kim     EXPECT_FALSE(logPath4.empty());
198*41a58d4fSBrandon Kim     EXPECT_NE(logEntryOut["Id"], nullptr);
199*41a58d4fSBrandon Kim     EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
200*41a58d4fSBrandon Kim 
201*41a58d4fSBrandon Kim     // Now send a LogEntry#5, we expect the LogEntry#3 to be deleted
202*41a58d4fSBrandon Kim     std::string logPath5;
203*41a58d4fSBrandon Kim     EXPECT_CALL(*mockFileWriterPtr, removeAll(logPath3)).WillOnce(Return(true));
204*41a58d4fSBrandon Kim     EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
205*41a58d4fSBrandon Kim         .WillOnce(DoAll(SaveArg<0>(&logPath5), SaveArg<1>(&logEntryOut),
206*41a58d4fSBrandon Kim                         Return(true)));
207*41a58d4fSBrandon Kim     EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
208*41a58d4fSBrandon Kim     EXPECT_FALSE(logPath5.empty());
20937bc0df1Skasunath     EXPECT_NE(logEntryOut["Id"], nullptr);
21037bc0df1Skasunath     EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
21137bc0df1Skasunath }
21237bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,OtherSchemaNoOdataIdTest)21337bc0df1Skasunath TEST_F(ExternalStorerFileTest, OtherSchemaNoOdataIdTest)
21437bc0df1Skasunath {
21537bc0df1Skasunath     // Try a another PDRs without @odata.id.
21637bc0df1Skasunath     std::string jsonStr = R"(
21737bc0df1Skasunath       {
21837bc0df1Skasunath         "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
21937bc0df1Skasunath         "Id":"Metrics"
22037bc0df1Skasunath       }
22137bc0df1Skasunath     )";
22237bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), false);
22337bc0df1Skasunath }
22437bc0df1Skasunath 
TEST_F(ExternalStorerFileTest,OtherSchemaTypeTest)22537bc0df1Skasunath TEST_F(ExternalStorerFileTest, OtherSchemaTypeTest)
22637bc0df1Skasunath {
22737bc0df1Skasunath     // A valid MemoryMetrics PDR.
22837bc0df1Skasunath     std::string jsonStr = R"(
22937bc0df1Skasunath       {
23037bc0df1Skasunath         "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
23137bc0df1Skasunath         "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
23237bc0df1Skasunath         "Id": "Metrics"
23337bc0df1Skasunath       }
23437bc0df1Skasunath     )";
23537bc0df1Skasunath     std::string exFolder =
23637bc0df1Skasunath         "/some/path/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics";
23737bc0df1Skasunath     nlohmann::json exJson = nlohmann::json::parse(jsonStr);
23837bc0df1Skasunath     EXPECT_CALL(*mockFileWriterPtr, createFile(exFolder, exJson))
23937bc0df1Skasunath         .WillOnce(Return(true));
24037bc0df1Skasunath     EXPECT_THAT(exStorer->publishJson(jsonStr), true);
24137bc0df1Skasunath }
24237bc0df1Skasunath 
24337bc0df1Skasunath } // namespace rde
24437bc0df1Skasunath } // namespace bios_bmc_smm_error_logger
245