1 #include "rde/external_storer_file.hpp"
2
3 #include <boost/asio/io_context.hpp>
4
5 #include <string_view>
6
7 #include <gmock/gmock-matchers.h>
8 #include <gmock/gmock.h>
9 #include <gtest/gtest.h>
10
11 namespace bios_bmc_smm_error_logger
12 {
13 namespace rde
14 {
15
16 using ::testing::_;
17 using ::testing::DoAll;
18 using ::testing::InSequence;
19 using ::testing::Return;
20 using ::testing::SaveArg;
21
22 class MockFileWriter : public FileHandlerInterface
23 {
24 public:
25 MOCK_METHOD(bool, createFolder, (const std::string& path),
26 (const, override));
27 MOCK_METHOD(bool, createFile,
28 (const std::string& path, const nlohmann::json& jsonPdr),
29 (const, override));
30 MOCK_METHOD(bool, removeAll, (const std::string& path), (const, override));
31 };
32
33 class ExternalStorerFileTest : public ::testing::Test
34 {
35 public:
ExternalStorerFileTest()36 ExternalStorerFileTest() :
37 conn(std::make_shared<sdbusplus::asio::connection>(io)),
38 mockFileWriter(std::make_unique<MockFileWriter>())
39 {
40 mockFileWriterPtr = dynamic_cast<MockFileWriter*>(mockFileWriter.get());
41 // Set the queue of LogEntry to 1 saved entry and 2 non saved entry
42 exStorer = std::make_unique<ExternalStorerFileInterface>(
43 conn, rootPath, std::move(mockFileWriter), 1, 2);
44 }
45
46 protected:
47 boost::asio::io_context io;
48 std::shared_ptr<sdbusplus::asio::connection> conn;
49
50 std::unique_ptr<FileHandlerInterface> mockFileWriter;
51 std::unique_ptr<ExternalStorerFileInterface> exStorer;
52 MockFileWriter* mockFileWriterPtr;
53 const std::string rootPath = "/some/path";
54 };
55
TEST_F(ExternalStorerFileTest,InvalidJsonTest)56 TEST_F(ExternalStorerFileTest, InvalidJsonTest)
57 {
58 // Try an invalid JSON.
59 std::string jsonStr = "Invalid JSON";
60 EXPECT_THAT(exStorer->publishJson(jsonStr), false);
61 }
62
TEST_F(ExternalStorerFileTest,NoOdataTypeFailureTest)63 TEST_F(ExternalStorerFileTest, NoOdataTypeFailureTest)
64 {
65 // Try a JSON without @odata.type.
66 std::string jsonStr = R"(
67 {
68 "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
69 "Id":"Metrics"
70 }
71 )";
72 EXPECT_THAT(exStorer->publishJson(jsonStr), false);
73 }
74
TEST_F(ExternalStorerFileTest,LogServiceNoOdataIdTest)75 TEST_F(ExternalStorerFileTest, LogServiceNoOdataIdTest)
76 {
77 // Try a LogService without @odata.id.
78 std::string jsonStr = R"(
79 {
80 "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
81 }
82 )";
83 EXPECT_THAT(exStorer->publishJson(jsonStr), false);
84 }
85
TEST_F(ExternalStorerFileTest,LogServiceNoIdTest)86 TEST_F(ExternalStorerFileTest, LogServiceNoIdTest)
87 {
88 // Try a LogService without Id.
89 std::string jsonStr = R"(
90 {
91 "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
92 "@odata.type": "#LogService.v1_1_0.LogService"
93 }
94 )";
95 EXPECT_THAT(exStorer->publishJson(jsonStr), false);
96 }
97
TEST_F(ExternalStorerFileTest,LogServiceTest)98 TEST_F(ExternalStorerFileTest, LogServiceTest)
99 {
100 // A valid LogService test.
101 std::string jsonStr = R"(
102 {
103 "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
104 "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
105 }
106 )";
107 std::string exServiceFolder =
108 "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
109 std::string exEntriesFolder =
110 "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
111 nlohmann::json exEntriesJson = "{}"_json;
112 nlohmann::json exServiceJson = nlohmann::json::parse(jsonStr);
113 EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
114 .WillOnce(Return(true));
115 EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
116 .WillOnce(Return(true));
117 EXPECT_THAT(exStorer->publishJson(jsonStr), true);
118 }
119
TEST_F(ExternalStorerFileTest,LogEntryWithoutLogServiceTest)120 TEST_F(ExternalStorerFileTest, LogEntryWithoutLogServiceTest)
121 {
122 // Try a LogEntry without sending a LogService first.
123 std::string jsonLogEntry = R"(
124 {
125 "@odata.type": "#LogEntry.v1_13_0.LogEntry"
126 }
127 )";
128 EXPECT_THAT(exStorer->publishJson(jsonLogEntry), false);
129 }
130
TEST_F(ExternalStorerFileTest,LogEntryTest)131 TEST_F(ExternalStorerFileTest, LogEntryTest)
132 {
133 InSequence s;
134 // Before sending a LogEntry, first we need to push a LogService.
135 std::string jsonLogSerivce = R"(
136 {
137 "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
138 "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
139 }
140 )";
141 std::string exServiceFolder =
142 "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
143 std::string exEntriesFolder =
144 "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
145 nlohmann::json exEntriesJson = "{}"_json;
146 nlohmann::json exServiceJson = nlohmann::json::parse(jsonLogSerivce);
147 EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
148 .WillOnce(Return(true));
149 EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
150 .WillOnce(Return(true));
151 EXPECT_THAT(exStorer->publishJson(jsonLogSerivce), true);
152
153 // Now send a LogEntry#1, which will not be deleted
154 std::string jsonLogEntry = R"(
155 {
156 "@odata.id": "/some/odata/id",
157 "@odata.type": "#LogEntry.v1_13_0.LogEntry"
158 }
159 )";
160 nlohmann::json logEntryOut;
161 std::string logPath1;
162 EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
163 .WillOnce(DoAll(SaveArg<0>(&logPath1), SaveArg<1>(&logEntryOut),
164 Return(true)));
165 EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
166 EXPECT_FALSE(logPath1.empty());
167 EXPECT_NE(logEntryOut["Id"], nullptr);
168 EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
169
170 // Now send a LogEntry#2, which will be the first to be deleted
171 std::string logPath2;
172 EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
173 .WillOnce(DoAll(SaveArg<0>(&logPath2), SaveArg<1>(&logEntryOut),
174 Return(true)));
175 EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
176 EXPECT_FALSE(logPath2.empty());
177 EXPECT_NE(logEntryOut["Id"], nullptr);
178 EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
179
180 // Now send a LogEntry#3
181 std::string logPath3;
182 EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
183 .WillOnce(DoAll(SaveArg<0>(&logPath3), SaveArg<1>(&logEntryOut),
184 Return(true)));
185 EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
186 EXPECT_FALSE(logPath3.empty());
187 EXPECT_NE(logEntryOut["Id"], nullptr);
188 EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
189
190 // Now send a LogEntry#4, we expect the LogEntry#2 to be deleted
191 std::string logPath4;
192 EXPECT_CALL(*mockFileWriterPtr, removeAll(logPath2)).WillOnce(Return(true));
193 EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
194 .WillOnce(DoAll(SaveArg<0>(&logPath4), SaveArg<1>(&logEntryOut),
195 Return(true)));
196 EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
197 EXPECT_FALSE(logPath4.empty());
198 EXPECT_NE(logEntryOut["Id"], nullptr);
199 EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
200
201 // Now send a LogEntry#5, we expect the LogEntry#3 to be deleted
202 std::string logPath5;
203 EXPECT_CALL(*mockFileWriterPtr, removeAll(logPath3)).WillOnce(Return(true));
204 EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
205 .WillOnce(DoAll(SaveArg<0>(&logPath5), SaveArg<1>(&logEntryOut),
206 Return(true)));
207 EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
208 EXPECT_FALSE(logPath5.empty());
209 EXPECT_NE(logEntryOut["Id"], nullptr);
210 EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
211 }
212
TEST_F(ExternalStorerFileTest,OtherSchemaNoOdataIdTest)213 TEST_F(ExternalStorerFileTest, OtherSchemaNoOdataIdTest)
214 {
215 // Try a another PDRs without @odata.id.
216 std::string jsonStr = R"(
217 {
218 "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
219 "Id":"Metrics"
220 }
221 )";
222 EXPECT_THAT(exStorer->publishJson(jsonStr), false);
223 }
224
TEST_F(ExternalStorerFileTest,OtherSchemaTypeTest)225 TEST_F(ExternalStorerFileTest, OtherSchemaTypeTest)
226 {
227 // A valid MemoryMetrics PDR.
228 std::string jsonStr = R"(
229 {
230 "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
231 "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
232 "Id": "Metrics"
233 }
234 )";
235 std::string exFolder =
236 "/some/path/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics";
237 nlohmann::json exJson = nlohmann::json::parse(jsonStr);
238 EXPECT_CALL(*mockFileWriterPtr, createFile(exFolder, exJson))
239 .WillOnce(Return(true));
240 EXPECT_THAT(exStorer->publishJson(jsonStr), true);
241 }
242
243 } // namespace rde
244 } // namespace bios_bmc_smm_error_logger
245