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