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