blob: 36b1d1440e3d31fed9707db8e851f4b775689ef6 [file] [log] [blame]
Matt Spinler97f7abc2019-11-06 09:40:23 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinler89fa0822019-07-17 13:54:30 -050016#include "extensions/openpower-pels/manager.hpp"
17#include "log_manager.hpp"
Matt Spinlere6b48f12020-04-02 09:51:39 -050018#include "mocks.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -050019#include "pel_utils.hpp"
20
Matt Spinlere6b48f12020-04-02 09:51:39 -050021#include <sdbusplus/test/sdbus_mock.hpp>
Matt Spinlera34ab722019-12-16 10:39:32 -060022#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler89fa0822019-07-17 13:54:30 -050023
Patrick Williams2544b412022-10-04 08:41:06 -050024#include <fstream>
25#include <regex>
26
Matt Spinler89fa0822019-07-17 13:54:30 -050027#include <gtest/gtest.h>
28
29using namespace openpower::pels;
30namespace fs = std::filesystem;
31
Matt Spinlere6b48f12020-04-02 09:51:39 -050032using ::testing::NiceMock;
Matt Spinler3dd17e92020-08-05 15:04:27 -050033using ::testing::Return;
Matt Spinlere6b48f12020-04-02 09:51:39 -050034
Matt Spinler05c2c6c2019-12-18 14:02:09 -060035class TestLogger
36{
37 public:
38 void log(const std::string& name, phosphor::logging::Entry::Level level,
39 const EventLogger::ADMap& additionalData)
40 {
41 errName = name;
42 errLevel = level;
43 ad = additionalData;
44 }
45
46 std::string errName;
47 phosphor::logging::Entry::Level errLevel;
48 EventLogger::ADMap ad;
49};
50
Matt Spinler89fa0822019-07-17 13:54:30 -050051class ManagerTest : public CleanPELFiles
52{
Matt Spinler6b1a5c82020-01-07 08:48:53 -060053 public:
Matt Spinlere6b48f12020-04-02 09:51:39 -050054 ManagerTest() :
55 bus(sdbusplus::get_mocked_new(&sdbusInterface)),
56 logManager(bus, "logging_path")
Matt Spinler6b1a5c82020-01-07 08:48:53 -060057 {
58 sd_event_default(&sdEvent);
Matt Spinler6b1a5c82020-01-07 08:48:53 -060059 }
60
61 ~ManagerTest()
62 {
63 sd_event_unref(sdEvent);
64 }
65
Matt Spinlere6b48f12020-04-02 09:51:39 -050066 NiceMock<sdbusplus::SdBusMock> sdbusInterface;
Patrick Williams45e83522022-07-22 19:26:52 -050067 sdbusplus::bus_t bus;
Matt Spinler6b1a5c82020-01-07 08:48:53 -060068 phosphor::logging::internal::Manager logManager;
69 sd_event* sdEvent;
Matt Spinler05c2c6c2019-12-18 14:02:09 -060070 TestLogger logger;
Matt Spinler89fa0822019-07-17 13:54:30 -050071};
72
73fs::path makeTempDir()
74{
75 char path[] = "/tmp/tempnameXXXXXX";
76 std::filesystem::path dir = mkdtemp(path);
77 return dir;
78}
79
Matt Spinler67456c22019-10-21 12:22:49 -050080std::optional<fs::path> findAnyPELInRepo()
81{
82 // PELs are named <timestamp>_<ID>
83 std::regex expr{"\\d+_\\d+"};
84
85 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs"))
86 {
87 if (std::regex_search(f.path().string(), expr))
88 {
89 return f.path();
90 }
91 }
92 return std::nullopt;
93}
94
Matt Spinler7e727a32020-07-07 15:00:17 -050095size_t countPELsInRepo()
96{
97 size_t count = 0;
98 std::regex expr{"\\d+_\\d+"};
99
100 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs"))
101 {
102 if (std::regex_search(f.path().string(), expr))
103 {
104 count++;
105 }
106 }
107 return count;
108}
109
Matt Spinlerff9cec22020-07-15 13:06:35 -0500110void deletePELFile(uint32_t id)
111{
112 char search[20];
113
114 sprintf(search, "\\d+_%.8X", id);
115 std::regex expr{search};
116
117 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs"))
118 {
119 if (std::regex_search(f.path().string(), expr))
120 {
121 fs::remove(f.path());
122 break;
123 }
124 }
125}
126
Matt Spinler89fa0822019-07-17 13:54:30 -0500127// Test that using the RAWPEL=<file> with the Manager::create() call gets
128// a PEL saved in the repository.
129TEST_F(ManagerTest, TestCreateWithPEL)
130{
Matt Spinlerc8705e22019-09-11 12:36:07 -0500131 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500132 std::make_unique<MockDataInterface>();
Matt Spinler89fa0822019-07-17 13:54:30 -0500133
Matt Spinlerd96fa602022-12-15 11:11:26 -0600134 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
135
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600136 openpower::pels::Manager manager{
137 logManager, std::move(dataIface),
138 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600139 std::placeholders::_2, std::placeholders::_3),
140 std::move(journal)};
Matt Spinler89fa0822019-07-17 13:54:30 -0500141
142 // Create a PEL, write it to a file, and pass that filename into
143 // the create function.
Matt Spinler42828bd2019-10-11 10:39:30 -0500144 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler89fa0822019-07-17 13:54:30 -0500145
146 fs::path pelFilename = makeTempDir() / "rawpel";
147 std::ofstream pelFile{pelFilename};
Matt Spinler42828bd2019-10-11 10:39:30 -0500148 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
Matt Spinler89fa0822019-07-17 13:54:30 -0500149 pelFile.close();
150
151 std::string adItem = "RAWPEL=" + pelFilename.string();
152 std::vector<std::string> additionalData{adItem};
153 std::vector<std::string> associations;
154
Matt Spinler367144c2019-09-19 15:33:52 -0500155 manager.create("error message", 42, 0,
156 phosphor::logging::Entry::Level::Error, additionalData,
Matt Spinler89fa0822019-07-17 13:54:30 -0500157 associations);
158
Matt Spinler67456c22019-10-21 12:22:49 -0500159 // Find the file in the PEL repository directory
160 auto pelPathInRepo = findAnyPELInRepo();
Matt Spinler89fa0822019-07-17 13:54:30 -0500161
Matt Spinler67456c22019-10-21 12:22:49 -0500162 EXPECT_TRUE(pelPathInRepo);
Matt Spinler89fa0822019-07-17 13:54:30 -0500163
Matt Spinler475e5742019-07-18 16:09:49 -0500164 // Now remove it based on its OpenBMC event log ID
165 manager.erase(42);
166
Matt Spinler67456c22019-10-21 12:22:49 -0500167 pelPathInRepo = findAnyPELInRepo();
Matt Spinler475e5742019-07-18 16:09:49 -0500168
Matt Spinler67456c22019-10-21 12:22:49 -0500169 EXPECT_FALSE(pelPathInRepo);
Matt Spinler475e5742019-07-18 16:09:49 -0500170
Matt Spinler89fa0822019-07-17 13:54:30 -0500171 fs::remove_all(pelFilename.parent_path());
172}
Matt Spinler67456c22019-10-21 12:22:49 -0500173
Matt Spinlere95fd012020-01-07 12:53:16 -0600174TEST_F(ManagerTest, TestCreateWithInvalidPEL)
175{
176 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500177 std::make_unique<MockDataInterface>();
Matt Spinlere95fd012020-01-07 12:53:16 -0600178
Matt Spinlerd96fa602022-12-15 11:11:26 -0600179 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
180
Matt Spinlere95fd012020-01-07 12:53:16 -0600181 openpower::pels::Manager manager{
182 logManager, std::move(dataIface),
183 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600184 std::placeholders::_2, std::placeholders::_3),
185 std::move(journal)};
Matt Spinlere95fd012020-01-07 12:53:16 -0600186
187 // Create a PEL, write it to a file, and pass that filename into
188 // the create function.
189 auto data = pelDataFactory(TestPELType::pelSimple);
190
191 // Truncate it to make it invalid.
192 data.resize(200);
193
194 fs::path pelFilename = makeTempDir() / "rawpel";
195 std::ofstream pelFile{pelFilename};
196 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
197 pelFile.close();
198
199 std::string adItem = "RAWPEL=" + pelFilename.string();
200 std::vector<std::string> additionalData{adItem};
201 std::vector<std::string> associations;
202
203 manager.create("error message", 42, 0,
204 phosphor::logging::Entry::Level::Error, additionalData,
205 associations);
206
207 // Run the event loop to log the bad PEL event
208 sdeventplus::Event e{sdEvent};
209 e.run(std::chrono::milliseconds(1));
210
211 PEL invalidPEL{data};
212 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.BadHostPEL");
213 EXPECT_EQ(logger.errLevel, phosphor::logging::Entry::Level::Error);
214 EXPECT_EQ(std::stoi(logger.ad["PLID"], nullptr, 16), invalidPEL.plid());
215 EXPECT_EQ(logger.ad["OBMC_LOG_ID"], "42");
216 EXPECT_EQ(logger.ad["SRC"], (*invalidPEL.primarySRC())->asciiString());
217 EXPECT_EQ(logger.ad["PEL_SIZE"], std::to_string(data.size()));
218
Matt Spinlerfe721892020-04-02 10:28:08 -0500219 // Check that the bad PEL data was saved to a file.
220 auto badPELData = readPELFile(getPELRepoPath() / "badPEL");
221 EXPECT_EQ(*badPELData, data);
222
Matt Spinlere95fd012020-01-07 12:53:16 -0600223 fs::remove_all(pelFilename.parent_path());
224}
225
Matt Spinler67456c22019-10-21 12:22:49 -0500226// Test that the message registry can be used to build a PEL.
227TEST_F(ManagerTest, TestCreateWithMessageRegistry)
228{
229 const auto registry = R"(
230{
231 "PELs":
232 [
233 {
234 "Name": "xyz.openbmc_project.Error.Test",
235 "Subsystem": "power_supply",
236 "ActionFlags": ["service_action", "report"],
237 "SRC":
238 {
239 "ReasonCode": "0x2030"
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800240 },
Vijay Lobo593a4c62021-06-16 14:25:26 -0500241 "Callouts": [
242 {
243 "CalloutList": [
244 {"Priority": "high", "Procedure": "bmc_code"},
245 {"Priority": "medium", "SymbolicFRU": "service_docs"}
246 ]
247 }
248 ],
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800249 "Documentation":
250 {
251 "Description": "A PGOOD Fault",
252 "Message": "PS had a PGOOD Fault"
Matt Spinler67456c22019-10-21 12:22:49 -0500253 }
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500254 },
255 {
256 "Name": "xyz.openbmc_project.Logging.Error.Default",
257 "Subsystem": "bmc_firmware",
258 "SRC":
259 {
260 "ReasonCode": "0x2031"
261 },
262 "Documentation":
263 {
264 "Description": "The entry used when no match found",
265 "Message": "This is a generic SRC"
266 }
Matt Spinler67456c22019-10-21 12:22:49 -0500267 }
268 ]
269}
270)";
271
Matt Spinler0d804ef2020-05-12 16:16:26 -0500272 auto path = getPELReadOnlyDataPath();
Matt Spinlerd4ffb652019-11-12 14:16:14 -0600273 fs::create_directories(path);
274 path /= "message_registry.json";
275
Matt Spinler67456c22019-10-21 12:22:49 -0500276 std::ofstream registryFile{path};
277 registryFile << registry;
278 registryFile.close();
279
Matt Spinler67456c22019-10-21 12:22:49 -0500280 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500281 std::make_unique<MockDataInterface>();
Matt Spinler67456c22019-10-21 12:22:49 -0500282
Sumit Kumar9d43a722021-08-24 09:46:19 -0500283 MockDataInterface* mockIface =
284 reinterpret_cast<MockDataInterface*>(dataIface.get());
285
286 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
287 "system/entry"};
288 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType))
289 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
290
Matt Spinlerd96fa602022-12-15 11:11:26 -0600291 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
292
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600293 openpower::pels::Manager manager{
294 logManager, std::move(dataIface),
295 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600296 std::placeholders::_2, std::placeholders::_3),
297 std::move(journal)};
Matt Spinler67456c22019-10-21 12:22:49 -0500298
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500299 std::vector<std::string> additionalData{"FOO=BAR"};
Matt Spinler67456c22019-10-21 12:22:49 -0500300 std::vector<std::string> associations;
301
302 // Create the event log to create the PEL from.
303 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
304 phosphor::logging::Entry::Level::Error, additionalData,
305 associations);
306
307 // Ensure a PEL was created in the repository
308 auto pelFile = findAnyPELInRepo();
309 ASSERT_TRUE(pelFile);
310
311 auto data = readPELFile(*pelFile);
312 PEL pel(*data);
313
314 // Spot check it. Other testcases cover the details.
315 EXPECT_TRUE(pel.valid());
316 EXPECT_EQ(pel.obmcLogID(), 33);
317 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
318 "BD612030 ");
Vijay Lobod354a392021-06-01 16:21:02 -0500319 // Check if the eventId creation is good
320 EXPECT_EQ(manager.getEventId(pel),
321 "BD612030 00000055 00000010 00000000 00000000 00000000 00000000 "
322 "00000000 00000000");
Vijay Lobo593a4c62021-06-16 14:25:26 -0500323 // Check if resolution property creation is good
324 EXPECT_EQ(manager.getResolution(pel),
Matt Spinlerea2873d2021-08-18 10:35:40 -0500325 "1. Priority: High, Procedure: BMC0001\n2. Priority: Medium, PN: "
Vijay Lobo593a4c62021-06-16 14:25:26 -0500326 "SVCDOCS\n");
Matt Spinler67456c22019-10-21 12:22:49 -0500327
328 // Remove it
329 manager.erase(33);
330 pelFile = findAnyPELInRepo();
331 EXPECT_FALSE(pelFile);
332
333 // Create an event log that can't be found in the registry.
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500334 // In this case, xyz.openbmc_project.Logging.Error.Default will
335 // be used as the key instead to find a registry match.
336 manager.create("xyz.openbmc_project.Error.Foo", 42, 0,
Matt Spinler67456c22019-10-21 12:22:49 -0500337 phosphor::logging::Entry::Level::Error, additionalData,
338 associations);
339
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500340 // Ensure a PEL was still created in the repository
Matt Spinler67456c22019-10-21 12:22:49 -0500341 pelFile = findAnyPELInRepo();
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500342 ASSERT_TRUE(pelFile);
343
344 data = readPELFile(*pelFile);
345 PEL newPEL(*data);
346
347 EXPECT_TRUE(newPEL.valid());
348 EXPECT_EQ(newPEL.obmcLogID(), 42);
349 EXPECT_EQ(newPEL.primarySRC().value()->asciiString(),
350 "BD8D2031 ");
351
352 // Check for both the original AdditionalData item as well as
353 // the ERROR_NAME item that should contain the error message
354 // property that wasn't found.
355 std::string errorName;
356 std::string adItem;
357
358 for (const auto& section : newPEL.optionalSections())
359 {
360 if (SectionID::userData == static_cast<SectionID>(section->header().id))
361 {
362 if (UserDataFormat::json ==
363 static_cast<UserDataFormat>(section->header().subType))
364 {
365 auto ud = static_cast<UserData*>(section.get());
366
367 // Check that there was a UserData section added that
368 // contains debug details about the device.
369 const auto& d = ud->data();
370 std::string jsonString{d.begin(), d.end()};
371 auto json = nlohmann::json::parse(jsonString);
372
373 if (json.contains("ERROR_NAME"))
374 {
375 errorName = json["ERROR_NAME"].get<std::string>();
376 }
377
378 if (json.contains("FOO"))
379 {
380 adItem = json["FOO"].get<std::string>();
381 }
382 }
383 }
384 if (!errorName.empty())
385 {
386 break;
387 }
388 }
389
390 EXPECT_EQ(errorName, "xyz.openbmc_project.Error.Foo");
391 EXPECT_EQ(adItem, "BAR");
Matt Spinler67456c22019-10-21 12:22:49 -0500392}
Matt Spinlera34ab722019-12-16 10:39:32 -0600393
394TEST_F(ManagerTest, TestDBusMethods)
395{
Matt Spinlera34ab722019-12-16 10:39:32 -0600396 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500397 std::make_unique<MockDataInterface>();
Matt Spinlera34ab722019-12-16 10:39:32 -0600398
Matt Spinlerd96fa602022-12-15 11:11:26 -0600399 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
400
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600401 Manager manager{logManager, std::move(dataIface),
402 std::bind(std::mem_fn(&TestLogger::log), &logger,
403 std::placeholders::_1, std::placeholders::_2,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600404 std::placeholders::_3),
405 std::move(journal)};
Matt Spinlera34ab722019-12-16 10:39:32 -0600406
407 // Create a PEL, write it to a file, and pass that filename into
408 // the create function so there's one in the repo.
409 auto data = pelDataFactory(TestPELType::pelSimple);
410
411 fs::path pelFilename = makeTempDir() / "rawpel";
412 std::ofstream pelFile{pelFilename};
413 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
414 pelFile.close();
415
416 std::string adItem = "RAWPEL=" + pelFilename.string();
417 std::vector<std::string> additionalData{adItem};
418 std::vector<std::string> associations;
419
420 manager.create("error message", 42, 0,
421 phosphor::logging::Entry::Level::Error, additionalData,
422 associations);
423
424 // getPELFromOBMCID
425 auto newData = manager.getPELFromOBMCID(42);
426 EXPECT_EQ(newData.size(), data.size());
427
428 // Read the PEL to get the ID for later
429 PEL pel{newData};
430 auto id = pel.id();
431
432 EXPECT_THROW(
433 manager.getPELFromOBMCID(id + 1),
434 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
435
436 // getPEL
437 auto unixfd = manager.getPEL(id);
438
439 // Get the size
440 struct stat s;
441 int r = fstat(unixfd, &s);
442 ASSERT_EQ(r, 0);
443 auto size = s.st_size;
444
445 // Open the FD and check the contents
446 FILE* fp = fdopen(unixfd, "r");
447 ASSERT_NE(fp, nullptr);
448
449 std::vector<uint8_t> fdData;
450 fdData.resize(size);
451 r = fread(fdData.data(), 1, size, fp);
452 EXPECT_EQ(r, size);
453
454 EXPECT_EQ(newData, fdData);
455
456 fclose(fp);
457
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600458 // Run the event loop to close the FD
459 sdeventplus::Event e{sdEvent};
460 e.run(std::chrono::milliseconds(1));
461
Matt Spinlera34ab722019-12-16 10:39:32 -0600462 EXPECT_THROW(
463 manager.getPEL(id + 1),
464 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
465
466 // hostAck
467 manager.hostAck(id);
468
469 EXPECT_THROW(
470 manager.hostAck(id + 1),
471 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
472
473 // hostReject
474 manager.hostReject(id, Manager::RejectionReason::BadPEL);
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600475
476 // Run the event loop to log the bad PEL event
477 e.run(std::chrono::milliseconds(1));
478
479 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.SentBadPELToHost");
480 EXPECT_EQ(id, std::stoi(logger.ad["BAD_ID"], nullptr, 16));
481
Matt Spinlera34ab722019-12-16 10:39:32 -0600482 manager.hostReject(id, Manager::RejectionReason::HostFull);
483
484 EXPECT_THROW(
485 manager.hostReject(id + 1, Manager::RejectionReason::BadPEL),
486 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
487
488 fs::remove_all(pelFilename.parent_path());
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500489
490 // GetPELIdFromBMCLogId
491 EXPECT_EQ(pel.id(), manager.getPELIdFromBMCLogId(pel.obmcLogID()));
492 EXPECT_THROW(
493 manager.getPELIdFromBMCLogId(pel.obmcLogID() + 1),
494 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ramesh Iyyar530efbf2021-06-24 06:22:22 -0500495
496 // GetBMCLogIdFromPELId
497 EXPECT_EQ(pel.obmcLogID(), manager.getBMCLogIdFromPELId(pel.id()));
498 EXPECT_THROW(
499 manager.getBMCLogIdFromPELId(pel.id() + 1),
500 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Matt Spinlera34ab722019-12-16 10:39:32 -0600501}
Matt Spinler19e72902020-01-24 11:05:20 -0600502
503// An ESEL from the wild
504const std::string esel{
505 "00 00 df 00 00 00 00 20 00 04 12 01 6f aa 00 00 "
506 "50 48 00 30 01 00 33 00 00 00 00 07 5c 69 cc 0d 00 00 00 07 5c d5 50 db "
507 "42 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 90 00 00 4e 90 00 00 4e "
508 "55 48 00 18 01 00 09 00 8a 03 40 00 00 00 00 00 ff ff 00 00 00 00 00 00 "
509 "50 53 00 50 01 01 00 00 02 00 00 09 33 2d 00 48 00 00 00 e0 00 00 10 00 "
510 "00 00 00 00 00 20 00 00 00 0c 00 02 00 00 00 fa 00 00 0c e4 00 00 00 12 "
511 "42 43 38 41 33 33 32 44 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
512 "20 20 20 20 20 20 20 20 55 44 00 1c 01 06 01 00 02 54 41 4b 00 00 00 06 "
513 "00 00 00 55 00 01 f9 20 00 00 00 00 55 44 00 24 01 06 01 00 01 54 41 4b "
514 "00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 23 01 00 02 00 05 00 00 "
515 "55 44 00 0c 01 0b 01 00 0f 01 00 00 55 44 00 10 01 04 01 00 0f 9f de 6a "
516 "00 01 00 00 55 44 00 7c 00 0c 01 00 00 13 0c 02 00 fa 0c e4 16 00 01 2c "
517 "0c 1c 16 00 00 fa 0a f0 14 00 00 fa 0b b8 14 00 00 be 09 60 12 00 01 2c "
518 "0d 7a 12 00 00 fa 0c 4e 10 00 00 fa 0c e4 10 00 00 be 0a 8c 16 00 01 2c "
519 "0c 1c 16 00 01 09 09 f6 16 00 00 fa 09 f6 14 00 00 fa 0b b8 14 00 00 fa "
520 "0a f0 14 00 00 be 08 ca 12 00 01 2c 0c e4 12 00 00 fa 0b 54 10 00 00 fa "
521 "0c 2d 10 00 00 be 08 ca 55 44 00 58 01 03 01 00 00 00 00 00 00 05 31 64 "
522 "00 00 00 00 00 05 0d d4 00 00 00 00 40 5f 06 e0 00 00 00 00 40 5d d2 00 "
523 "00 00 00 00 40 57 d3 d0 00 00 00 00 40 58 f6 a0 00 00 00 00 40 54 c9 34 "
524 "00 00 00 00 40 55 9a 10 00 00 00 00 40 4c 0a 80 00 00 00 00 00 00 27 14 "
525 "55 44 01 84 01 01 01 00 48 6f 73 74 62 6f 6f 74 20 42 75 69 6c 64 20 49 "
526 "44 3a 20 68 6f 73 74 62 6f 6f 74 2d 66 65 63 37 34 64 66 2d 70 30 61 38 "
527 "37 64 63 34 2f 68 62 69 63 6f 72 65 2e 62 69 6e 00 49 42 4d 2d 77 69 74 "
528 "68 65 72 73 70 6f 6f 6e 2d 4f 50 39 2d 76 32 2e 34 2d 39 2e 32 33 34 0a "
529 "09 6f 70 2d 62 75 69 6c 64 2d 38 32 66 34 63 66 30 0a 09 62 75 69 6c 64 "
530 "72 6f 6f 74 2d 32 30 31 39 2e 30 35 2e 32 2d 31 30 2d 67 38 39 35 39 31 "
531 "31 34 0a 09 73 6b 69 62 6f 6f 74 2d 76 36 2e 35 2d 31 38 2d 67 34 37 30 "
532 "66 66 62 35 66 32 39 64 37 0a 09 68 6f 73 74 62 6f 6f 74 2d 66 65 63 37 "
533 "34 64 66 2d 70 30 61 38 37 64 63 34 0a 09 6f 63 63 2d 65 34 35 39 37 61 "
534 "62 0a 09 6c 69 6e 75 78 2d 35 2e 32 2e 31 37 2d 6f 70 65 6e 70 6f 77 65 "
535 "72 31 2d 70 64 64 63 63 30 33 33 0a 09 70 65 74 69 74 62 6f 6f 74 2d 76 "
536 "31 2e 31 30 2e 34 0a 09 6d 61 63 68 69 6e 65 2d 78 6d 6c 2d 63 36 32 32 "
537 "63 62 35 2d 70 37 65 63 61 62 33 64 0a 09 68 6f 73 74 62 6f 6f 74 2d 62 "
538 "69 6e 61 72 69 65 73 2d 36 36 65 39 61 36 30 0a 09 63 61 70 70 2d 75 63 "
539 "6f 64 65 2d 70 39 2d 64 64 32 2d 76 34 0a 09 73 62 65 2d 36 30 33 33 30 "
540 "65 30 0a 09 68 63 6f 64 65 2d 68 77 30 39 32 31 31 39 61 2e 6f 70 6d 73 "
541 "74 0a 00 00 55 44 00 70 01 04 01 00 0f 9f de 6a 00 05 00 00 07 5f 1d f4 "
542 "30 32 43 59 34 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
543 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
544 "0b ac 54 02 59 41 31 39 33 34 36 39 37 30 35 38 00 00 00 00 00 00 05 22 "
545 "a1 58 01 8a 00 58 40 20 17 18 4d 2c 00 00 00 fc 01 a1 00 00 55 44 00 14 "
546 "01 08 01 00 00 00 00 01 00 00 00 5a 00 00 00 05 55 44 03 fc 01 15 31 00 "
547 "01 28 00 42 46 41 50 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 f4 "
548 "00 00 00 00 00 00 03 f4 00 00 00 0b 00 00 00 00 00 00 00 3d 2c 9b c2 84 "
549 "00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 09 "
550 "00 00 00 00 00 11 bd 20 00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 "
551 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 00 00 00 01 2c "
552 "00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0c 1c 00 00 00 64 00 00 00 3d "
553 "2c 9b d1 11 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 "
554 "00 00 00 0a 00 00 00 00 00 13 b5 a0 00 00 00 00 00 01 f8 80 00 00 00 00 "
555 "00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 "
556 "00 00 00 be 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0a 8c 00 00 00 64 "
557 "00 00 00 3d 2c 9b df 98 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 "
558 "00 00 00 00 00 00 00 0b 00 00 00 00 00 15 ae 20 00 00 00 00 00 01 f8 80 "
559 "00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 "
560 "00 00 00 00 00 00 00 fa 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0c e4 "
561 "00 00 00 64 00 00 00 3d 2c 9b ea b7 00 00 01 e4 00 48 43 4f fb ed 70 b1 "
562 "00 00 02 01 00 00 00 00 00 00 00 0c 00 00 00 00 00 17 a6 a0 00 00 00 00 "
563 "00 01 f8 80 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 "
564 "00 00 00 12 00 00 00 00 00 00 00 fa 00 00 00 00 00 00 07 d0 00 00 00 00 "
565 "00 00 0c 4e 00 00 00 64 00 00 00 3d 2c 9b f6 27 00 00 01 e4 00 48 43 4f "
566 "fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 0d 00 00 00 00 00 19 9f 20 "
567 "00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 "
568 "00 00 00 00 00 00 00 12 00 00 00 00 00 00 01 2c 00 00 00 00 00 00 07 d0 "
569 "00 00 00 00 00 00 0d 7a 00 00 00 64 00 00 00 3d 2c 9c 05 75 00 00 01 e4 "
570 "00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 0e 00 00 00 00 "
571 "00 1b 97 a0 00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 00 00 00 00 "
572 "00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 be 00 00 00 00 "
573 "00 00 07 d0 00 00 00 00 00 00 09 60 00 00 00 64 00 00 00 3d 2c 9c 11 29 "
574 "00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 0f "
575 "00 00 00 00 00 1d 90 20 00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 "
576 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 fa "
577 "00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0b b8 00 00 00 64 00 00 00 3d "
578 "2c 9c 1c 45 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 "
579 "00 00 00 10 00 00 00 00 00 1f 88 a0 00 00 00 00 00 01 f8 80 00 00 00 00 "
580 "00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 00 "
581 "00 00 00 fa 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0a f0 00 00 00 64 "
582 "00 00 00 3d 2c 9c 2b 14 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 "
583 "00 00 00 00 00 00 00 11 00 00 00 00 00 21 81 20 00 00 00 00 00 01 f8 80 "
584 "00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 "
585 "00 00 00 00 00 00 01 2c 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0c 1c "
586 "00 00 00 64 00 00 00 3d 2d 6d 8f 9e 00 00 01 e4 00 00 43 4f 52 d7 9c 36 "
587 "00 00 04 73 00 00 00 1c 00 00 00 3d 2d 6d 99 ac 00 00 01 e4 00 10 43 4f "
588 "3f f2 02 3d 00 00 05 58 00 00 00 00 02 00 00 01 00 00 00 00 00 00 00 40 "
589 "00 00 00 2c 55 44 00 30 01 15 31 00 01 28 00 42 46 41 50 49 5f 44 42 47 "
590 "00 00 00 00 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 28 00 00 00 00 "
591 "00 00 00 00 55 44 01 74 01 15 31 00 01 28 00 42 46 41 50 49 5f 49 00 00 "
592 "00 00 00 00 00 00 00 00 00 00 01 6c 00 00 00 00 00 00 01 6c 00 00 00 0b "
593 "00 00 00 00 00 00 00 3c 0d 52 18 5e 00 00 01 e4 00 08 43 4f 46 79 94 13 "
594 "00 00 0a 5b 00 00 00 00 00 00 2c 00 00 00 00 24 00 00 00 3c 0d 6b 26 6c "
595 "00 00 01 e4 00 00 43 4f 4e 9b 18 74 00 00 01 03 00 00 00 1c 00 00 00 3c "
596 "12 b9 2d 13 00 00 01 e4 00 00 43 4f ea 31 ed d4 00 00 05 c4 00 00 00 1c "
597 "00 00 00 3c 13 02 73 53 00 00 01 e4 00 00 43 4f ea 31 ed d4 00 00 05 c4 "
598 "00 00 00 1c 00 00 00 3c 13 04 7c 94 00 00 01 e4 00 00 43 4f ea 31 ed d4 "
599 "00 00 05 c4 00 00 00 1c 00 00 00 3c 13 06 ad e1 00 00 01 e4 00 00 43 4f "
600 "ea 31 ed d4 00 00 05 c4 00 00 00 1c 00 00 00 3c 13 07 3f 77 00 00 01 e4 "
601 "00 00 43 4f 5e 4a 55 32 00 00 10 f2 00 00 00 1c 00 00 00 3c 13 07 4e e4 "
602 "00 00 01 e4 00 00 43 4f 5e 4a 55 32 00 00 0d 68 00 00 00 1c 00 00 00 3c "
603 "13 36 79 18 00 00 01 e4 00 00 43 4f ea 31 ed d4 00 00 05 c4 00 00 00 1c "
604 "00 00 00 3d 2c 9c 36 70 00 00 01 e4 00 00 43 4f 23 45 90 97 00 00 02 47 "
605 "00 00 00 1c 00 00 00 3d 2d 6d a3 ed 00 00 01 e4 00 08 43 4f 74 3a 5b 1a "
606 "00 00 04 cc 00 00 00 00 02 00 00 01 00 00 00 24 55 44 00 30 01 15 31 00 "
607 "01 28 00 42 53 43 41 4e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 "
608 "00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 00"};
609
610TEST_F(ManagerTest, TestESELToRawData)
611{
612 auto data = Manager::eselToRawData(esel);
613
614 EXPECT_EQ(data.size(), 2464);
615
616 PEL pel{data};
617 EXPECT_TRUE(pel.valid());
618}
619
620TEST_F(ManagerTest, TestCreateWithESEL)
621{
622 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500623 std::make_unique<MockDataInterface>();
Matt Spinler19e72902020-01-24 11:05:20 -0600624
Matt Spinlerd96fa602022-12-15 11:11:26 -0600625 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
626
Matt Spinler19e72902020-01-24 11:05:20 -0600627 openpower::pels::Manager manager{
628 logManager, std::move(dataIface),
629 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600630 std::placeholders::_2, std::placeholders::_3),
631 std::move(journal)};
Matt Spinler19e72902020-01-24 11:05:20 -0600632
633 {
634 std::string adItem = "ESEL=" + esel;
635 std::vector<std::string> additionalData{adItem};
636 std::vector<std::string> associations;
637
638 manager.create("error message", 37, 0,
639 phosphor::logging::Entry::Level::Error, additionalData,
640 associations);
641
642 auto data = manager.getPELFromOBMCID(37);
643 PEL pel{data};
644 EXPECT_TRUE(pel.valid());
645 }
646
647 // Now an invalid one
648 {
649 std::string adItem = "ESEL=" + esel;
650
651 // Crop it
652 adItem.resize(adItem.size() - 300);
653
654 std::vector<std::string> additionalData{adItem};
655 std::vector<std::string> associations;
656
657 manager.create("error message", 38, 0,
658 phosphor::logging::Entry::Level::Error, additionalData,
659 associations);
660
661 EXPECT_THROW(
662 manager.getPELFromOBMCID(38),
663 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
664
665 // Run the event loop to log the bad PEL event
666 sdeventplus::Event e{sdEvent};
667 e.run(std::chrono::milliseconds(1));
668
669 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.BadHostPEL");
670 EXPECT_EQ(logger.errLevel, phosphor::logging::Entry::Level::Error);
671 }
672}
Matt Spinler7e727a32020-07-07 15:00:17 -0500673
674// Test that PELs will be pruned when necessary
675TEST_F(ManagerTest, TestPruning)
676{
677 sdeventplus::Event e{sdEvent};
678
679 std::unique_ptr<DataInterfaceBase> dataIface =
680 std::make_unique<MockDataInterface>();
681
Matt Spinlerd96fa602022-12-15 11:11:26 -0600682 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
683
Matt Spinler7e727a32020-07-07 15:00:17 -0500684 openpower::pels::Manager manager{
685 logManager, std::move(dataIface),
686 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600687 std::placeholders::_2, std::placeholders::_3),
688 std::move(journal)};
Matt Spinler7e727a32020-07-07 15:00:17 -0500689
690 // Create 25 1000B (4096B on disk each, which is what is used for pruning)
691 // BMC non-informational PELs in the 100KB repository. After the 24th one,
692 // the repo will be 96% full and a prune should be triggered to remove all
693 // but 7 to get under 30% full. Then when the 25th is added there will be
694 // 8 left.
695
696 auto dir = makeTempDir();
697 for (int i = 1; i <= 25; i++)
698 {
699 auto data = pelFactory(42, 'O', 0x40, 0x8800, 1000);
700
701 fs::path pelFilename = dir / "rawpel";
702 std::ofstream pelFile{pelFilename};
703 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
704 pelFile.close();
705
706 std::string adItem = "RAWPEL=" + pelFilename.string();
707 std::vector<std::string> additionalData{adItem};
708 std::vector<std::string> associations;
709
710 manager.create("error message", 42, 0,
711 phosphor::logging::Entry::Level::Error, additionalData,
712 associations);
713
714 // Simulate the code getting back to the event loop
715 // after each create.
716 e.run(std::chrono::milliseconds(1));
717
718 if (i < 24)
719 {
720 EXPECT_EQ(countPELsInRepo(), i);
721 }
722 else if (i == 24)
723 {
724 // Prune occured
725 EXPECT_EQ(countPELsInRepo(), 7);
726 }
727 else // i == 25
728 {
729 EXPECT_EQ(countPELsInRepo(), 8);
730 }
731 }
732
733 try
734 {
735 // Make sure the 8 newest ones are still found.
736 for (uint32_t i = 0; i < 8; i++)
737 {
738 manager.getPEL(0x50000012 + i);
739 }
740 }
Patrick Williams66491c62021-10-06 12:23:37 -0500741 catch (
742 const sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument&
Matt Spinlerbe952d22022-07-01 11:30:11 -0500743 ex)
Matt Spinler7e727a32020-07-07 15:00:17 -0500744 {
745 ADD_FAILURE() << "PELs should have all been found";
746 }
747
748 fs::remove_all(dir);
749}
Matt Spinlerff9cec22020-07-15 13:06:35 -0500750
751// Test that manually deleting a PEL file will be recognized by the code.
752TEST_F(ManagerTest, TestPELManualDelete)
753{
754 sdeventplus::Event e{sdEvent};
755
756 std::unique_ptr<DataInterfaceBase> dataIface =
757 std::make_unique<MockDataInterface>();
758
Matt Spinlerd96fa602022-12-15 11:11:26 -0600759 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
760
Matt Spinlerff9cec22020-07-15 13:06:35 -0500761 openpower::pels::Manager manager{
762 logManager, std::move(dataIface),
763 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600764 std::placeholders::_2, std::placeholders::_3),
765 std::move(journal)};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500766
767 auto data = pelDataFactory(TestPELType::pelSimple);
768 auto dir = makeTempDir();
769 fs::path pelFilename = dir / "rawpel";
770
771 std::string adItem = "RAWPEL=" + pelFilename.string();
772 std::vector<std::string> additionalData{adItem};
773 std::vector<std::string> associations;
774
775 // Add 20 PELs, they will get incrementing IDs like
776 // 0x50000001, 0x50000002, etc.
777 for (int i = 1; i <= 20; i++)
778 {
779 std::ofstream pelFile{pelFilename};
780 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
781 pelFile.close();
782
783 manager.create("error message", 42, 0,
784 phosphor::logging::Entry::Level::Error, additionalData,
785 associations);
786
787 // Sanity check this ID is really there so we can test
788 // it was deleted later. This will throw an exception if
789 // not present.
790 manager.getPEL(0x50000000 + i);
791
792 // Run an event loop pass where the internal FD is deleted
793 // after the getPEL function call.
794 e.run(std::chrono::milliseconds(1));
795 }
796
797 EXPECT_EQ(countPELsInRepo(), 20);
798
799 deletePELFile(0x50000001);
800
801 // Run a single event loop pass so the inotify event can run
802 e.run(std::chrono::milliseconds(1));
803
804 EXPECT_EQ(countPELsInRepo(), 19);
805
806 EXPECT_THROW(
807 manager.getPEL(0x50000001),
808 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
809
810 // Delete a few more, they should all get handled in the same
811 // event loop pass
812 std::vector<uint32_t> toDelete{0x50000002, 0x50000003, 0x50000004,
813 0x50000005, 0x50000006};
814 std::for_each(toDelete.begin(), toDelete.end(),
815 [](auto i) { deletePELFile(i); });
816
817 e.run(std::chrono::milliseconds(1));
818
819 EXPECT_EQ(countPELsInRepo(), 14);
820
821 std::for_each(toDelete.begin(), toDelete.end(), [&manager](const auto i) {
822 EXPECT_THROW(
823 manager.getPEL(i),
824 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
825 });
826
827 fs::remove_all(dir);
828}
829
830// Test that deleting all PELs at once is handled OK.
831TEST_F(ManagerTest, TestPELManualDeleteAll)
832{
833 sdeventplus::Event e{sdEvent};
834
835 std::unique_ptr<DataInterfaceBase> dataIface =
836 std::make_unique<MockDataInterface>();
837
Matt Spinlerd96fa602022-12-15 11:11:26 -0600838 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
839
Matt Spinlerff9cec22020-07-15 13:06:35 -0500840 openpower::pels::Manager manager{
841 logManager, std::move(dataIface),
842 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600843 std::placeholders::_2, std::placeholders::_3),
844 std::move(journal)};
Matt Spinlerff9cec22020-07-15 13:06:35 -0500845
846 auto data = pelDataFactory(TestPELType::pelSimple);
847 auto dir = makeTempDir();
848 fs::path pelFilename = dir / "rawpel";
849
850 std::string adItem = "RAWPEL=" + pelFilename.string();
851 std::vector<std::string> additionalData{adItem};
852 std::vector<std::string> associations;
853
854 // Add 200 PELs, they will get incrementing IDs like
855 // 0x50000001, 0x50000002, etc.
856 for (int i = 1; i <= 200; i++)
857 {
858 std::ofstream pelFile{pelFilename};
859 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
860 pelFile.close();
861
862 manager.create("error message", 42, 0,
863 phosphor::logging::Entry::Level::Error, additionalData,
864 associations);
865
866 // Sanity check this ID is really there so we can test
867 // it was deleted later. This will throw an exception if
868 // not present.
869 manager.getPEL(0x50000000 + i);
870
871 // Run an event loop pass where the internal FD is deleted
872 // after the getPEL function call.
873 e.run(std::chrono::milliseconds(1));
874 }
875
876 // Delete them all at once
877 auto logPath = getPELRepoPath() / "logs";
Sumit Kumar1d8835b2021-06-07 09:35:30 -0500878 std::string cmd = "rm " + logPath.string() + "/*_*";
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500879
880 {
881 auto rc = system(cmd.c_str());
882 EXPECT_EQ(rc, 0);
883 }
Matt Spinlerff9cec22020-07-15 13:06:35 -0500884
885 EXPECT_EQ(countPELsInRepo(), 0);
886
887 // It will take 5 event loop passes to process them all
888 for (int i = 0; i < 5; i++)
889 {
890 e.run(std::chrono::milliseconds(1));
891 }
892
893 for (int i = 1; i <= 200; i++)
894 {
895 EXPECT_THROW(
896 manager.getPEL(0x50000000 + i),
897 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
898 }
899
900 fs::remove_all(dir);
901}
Matt Spinler3dd17e92020-08-05 15:04:27 -0500902
903// Test that fault LEDs are turned on when PELs are created
904TEST_F(ManagerTest, TestServiceIndicators)
905{
906 std::unique_ptr<DataInterfaceBase> dataIface =
907 std::make_unique<MockDataInterface>();
908
909 MockDataInterface* mockIface =
910 reinterpret_cast<MockDataInterface*>(dataIface.get());
911
Sumit Kumar9d43a722021-08-24 09:46:19 -0500912 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
913 "system/entry"};
914 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType))
915 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
916
Matt Spinlerd96fa602022-12-15 11:11:26 -0600917 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
918
Matt Spinler3dd17e92020-08-05 15:04:27 -0500919 openpower::pels::Manager manager{
920 logManager, std::move(dataIface),
921 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -0600922 std::placeholders::_2, std::placeholders::_3),
923 std::move(journal)};
Matt Spinler3dd17e92020-08-05 15:04:27 -0500924
925 // Add a PEL with a callout as if hostboot added it
926 {
927 EXPECT_CALL(*mockIface, getInventoryFromLocCode("U42", 0, true))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600928 .WillOnce(
929 Return(std::vector<std::string>{"/system/chassis/processor"}));
Matt Spinler3dd17e92020-08-05 15:04:27 -0500930
Matt Spinler993168d2021-04-07 16:05:03 -0500931 EXPECT_CALL(*mockIface,
932 setFunctional("/system/chassis/processor", false))
Matt Spinler3dd17e92020-08-05 15:04:27 -0500933 .Times(1);
934
935 // This hostboot PEL has a single hardware callout in it.
936 auto data = pelFactory(1, 'B', 0x20, 0xA400, 500);
937
938 fs::path pelFilename = makeTempDir() / "rawpel";
939 std::ofstream pelFile{pelFilename};
940 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
941 pelFile.close();
942
943 std::string adItem = "RAWPEL=" + pelFilename.string();
944 std::vector<std::string> additionalData{adItem};
945 std::vector<std::string> associations;
946
947 manager.create("error message", 42, 0,
948 phosphor::logging::Entry::Level::Error, additionalData,
949 associations);
950
951 fs::remove_all(pelFilename.parent_path());
952 }
953
954 // Add a BMC PEL with a callout that uses the message registry
955 {
956 std::vector<std::string> names{"systemA"};
957 EXPECT_CALL(*mockIface, getSystemNames)
958 .Times(1)
Matt Spinler1ab66962020-10-29 13:21:44 -0500959 .WillOnce(Return(names));
Matt Spinler3dd17e92020-08-05 15:04:27 -0500960
961 EXPECT_CALL(*mockIface, expandLocationCode("P42-C23", 0))
962 .WillOnce(Return("U42-P42-C23"));
963
964 // First call to this is when building the Callout section
965 EXPECT_CALL(*mockIface, getInventoryFromLocCode("P42-C23", 0, false))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600966 .WillOnce(
967 Return(std::vector<std::string>{"/system/chassis/processor"}));
Matt Spinler3dd17e92020-08-05 15:04:27 -0500968
969 // Second call to this is finding the associated LED group
970 EXPECT_CALL(*mockIface, getInventoryFromLocCode("U42-P42-C23", 0, true))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600971 .WillOnce(
972 Return(std::vector<std::string>{"/system/chassis/processor"}));
Matt Spinler3dd17e92020-08-05 15:04:27 -0500973
Matt Spinler993168d2021-04-07 16:05:03 -0500974 EXPECT_CALL(*mockIface,
975 setFunctional("/system/chassis/processor", false))
Matt Spinler3dd17e92020-08-05 15:04:27 -0500976 .Times(1);
977
978 const auto registry = R"(
979 {
980 "PELs":
981 [
982 {
983 "Name": "xyz.openbmc_project.Error.Test",
984 "Subsystem": "power_supply",
985 "ActionFlags": ["service_action", "report"],
986 "SRC":
987 {
988 "ReasonCode": "0x2030"
989 },
990 "Callouts": [
991 {
992 "CalloutList": [
993 {"Priority": "high", "LocCode": "P42-C23"}
994 ]
995 }
996 ],
997 "Documentation":
998 {
999 "Description": "Test Error",
1000 "Message": "Test Error"
1001 }
1002 }
1003 ]
1004 })";
1005
1006 auto path = getPELReadOnlyDataPath();
1007 fs::create_directories(path);
1008 path /= "message_registry.json";
1009
1010 std::ofstream registryFile{path};
1011 registryFile << registry;
1012 registryFile.close();
1013
1014 std::vector<std::string> additionalData;
1015 std::vector<std::string> associations;
1016
1017 manager.create("xyz.openbmc_project.Error.Test", 42, 0,
1018 phosphor::logging::Entry::Level::Error, additionalData,
1019 associations);
1020 }
1021}
Sumit Kumar2ccdcef2021-07-31 10:04:58 -05001022
1023// Test for duplicate PELs moved to archive folder
1024TEST_F(ManagerTest, TestDuplicatePEL)
1025{
1026 sdeventplus::Event e{sdEvent};
1027 size_t count = 0;
1028
1029 std::unique_ptr<DataInterfaceBase> dataIface =
1030 std::make_unique<MockDataInterface>();
1031
Matt Spinlerd96fa602022-12-15 11:11:26 -06001032 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
1033
Sumit Kumar2ccdcef2021-07-31 10:04:58 -05001034 openpower::pels::Manager manager{
1035 logManager, std::move(dataIface),
1036 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -06001037 std::placeholders::_2, std::placeholders::_3),
1038 std::move(journal)};
Sumit Kumar2ccdcef2021-07-31 10:04:58 -05001039
1040 for (int i = 0; i < 2; i++)
1041 {
1042 // This hostboot PEL has a single hardware callout in it.
1043 auto data = pelFactory(1, 'B', 0x20, 0xA400, 500);
1044
1045 fs::path pelFilename = makeTempDir() / "rawpel";
1046 std::ofstream pelFile{pelFilename};
1047 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
1048 pelFile.close();
1049
1050 std::string adItem = "RAWPEL=" + pelFilename.string();
1051 std::vector<std::string> additionalData{adItem};
1052 std::vector<std::string> associations;
1053
1054 manager.create("error message", 42, 0,
1055 phosphor::logging::Entry::Level::Error, additionalData,
1056 associations);
1057
1058 e.run(std::chrono::milliseconds(1));
1059 }
1060
1061 for (auto& f :
1062 fs::directory_iterator(getPELRepoPath() / "logs" / "archive"))
1063 {
1064 if (fs::is_regular_file(f.path()))
1065 {
1066 count++;
1067 }
1068 }
1069
1070 // Get count of PELs in the repository & in archive directtory
1071 EXPECT_EQ(countPELsInRepo(), 1);
1072 EXPECT_EQ(count, 1);
1073}
Sumit Kumar3e274432021-09-14 06:37:56 -05001074
1075// Test termination bit set for pel with critical system termination severity
1076TEST_F(ManagerTest, TestTerminateBitWithPELSevCriticalSysTerminate)
1077{
1078 const auto registry = R"(
1079{
1080 "PELs":
1081 [
1082 {
1083 "Name": "xyz.openbmc_project.Error.Test",
1084 "Subsystem": "power_supply",
1085 "Severity": "critical_system_term",
1086 "ActionFlags": ["service_action", "report"],
1087 "SRC":
1088 {
1089 "ReasonCode": "0x2030"
1090 },
1091 "Documentation":
1092 {
1093 "Description": "A PGOOD Fault",
1094 "Message": "PS had a PGOOD Fault"
1095 }
1096 }
1097 ]
1098}
1099)";
1100
1101 auto path = getPELReadOnlyDataPath();
1102 fs::create_directories(path);
1103 path /= "message_registry.json";
1104
1105 std::ofstream registryFile{path};
1106 registryFile << registry;
1107 registryFile.close();
1108
1109 std::unique_ptr<DataInterfaceBase> dataIface =
1110 std::make_unique<MockDataInterface>();
1111
1112 MockDataInterface* mockIface =
1113 reinterpret_cast<MockDataInterface*>(dataIface.get());
1114
1115 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1116 "system/entry"};
1117 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType))
1118 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
1119
Matt Spinlerd96fa602022-12-15 11:11:26 -06001120 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>();
1121
Sumit Kumar3e274432021-09-14 06:37:56 -05001122 openpower::pels::Manager manager{
1123 logManager, std::move(dataIface),
1124 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
Matt Spinlerd96fa602022-12-15 11:11:26 -06001125 std::placeholders::_2, std::placeholders::_3),
1126 std::move(journal)};
Sumit Kumar3e274432021-09-14 06:37:56 -05001127
1128 std::vector<std::string> additionalData{"FOO=BAR"};
1129 std::vector<std::string> associations;
1130
1131 // Create the event log to create the PEL from.
1132 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
1133 phosphor::logging::Entry::Level::Error, additionalData,
1134 associations);
1135
1136 // Ensure a PEL was created in the repository
1137 auto pelData = findAnyPELInRepo();
1138 ASSERT_TRUE(pelData);
1139
1140 auto getPELData = readPELFile(*pelData);
1141 PEL pel(*getPELData);
1142
1143 // Spot check it. Other testcases cover the details.
1144 EXPECT_TRUE(pel.valid());
1145
1146 // Check for terminate bit set
1147 auto& hexwords = pel.primarySRC().value()->hexwordData();
1148 EXPECT_EQ(hexwords[3] & 0x20000000, 0x20000000);
1149}
Matt Spinler0003af12022-06-08 10:46:17 -05001150
1151TEST_F(ManagerTest, TestSanitizeFieldforDBus)
1152{
1153 std::string base{"(test0!}\n\t ~"};
1154 auto string = base;
1155 string += char{' ' - 1};
1156 string += char{'~' + 1};
1157 string += char{0};
1158 string += char{static_cast<char>(0xFF)};
1159
1160 // convert the last four chars to spaces
1161 EXPECT_EQ(Manager::sanitizeFieldForDBus(string), base + " ");
1162}