blob: b27ca60b42de734904fdb95f06b33b4a89de5416 [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 Spinler05c2c6c2019-12-18 14:02:09 -0600134 openpower::pels::Manager manager{
135 logManager, std::move(dataIface),
136 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
137 std::placeholders::_2, std::placeholders::_3)};
Matt Spinler89fa0822019-07-17 13:54:30 -0500138
139 // Create a PEL, write it to a file, and pass that filename into
140 // the create function.
Matt Spinler42828bd2019-10-11 10:39:30 -0500141 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler89fa0822019-07-17 13:54:30 -0500142
143 fs::path pelFilename = makeTempDir() / "rawpel";
144 std::ofstream pelFile{pelFilename};
Matt Spinler42828bd2019-10-11 10:39:30 -0500145 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
Matt Spinler89fa0822019-07-17 13:54:30 -0500146 pelFile.close();
147
148 std::string adItem = "RAWPEL=" + pelFilename.string();
149 std::vector<std::string> additionalData{adItem};
150 std::vector<std::string> associations;
151
Matt Spinler367144c2019-09-19 15:33:52 -0500152 manager.create("error message", 42, 0,
153 phosphor::logging::Entry::Level::Error, additionalData,
Matt Spinler89fa0822019-07-17 13:54:30 -0500154 associations);
155
Matt Spinler67456c22019-10-21 12:22:49 -0500156 // Find the file in the PEL repository directory
157 auto pelPathInRepo = findAnyPELInRepo();
Matt Spinler89fa0822019-07-17 13:54:30 -0500158
Matt Spinler67456c22019-10-21 12:22:49 -0500159 EXPECT_TRUE(pelPathInRepo);
Matt Spinler89fa0822019-07-17 13:54:30 -0500160
Matt Spinler475e5742019-07-18 16:09:49 -0500161 // Now remove it based on its OpenBMC event log ID
162 manager.erase(42);
163
Matt Spinler67456c22019-10-21 12:22:49 -0500164 pelPathInRepo = findAnyPELInRepo();
Matt Spinler475e5742019-07-18 16:09:49 -0500165
Matt Spinler67456c22019-10-21 12:22:49 -0500166 EXPECT_FALSE(pelPathInRepo);
Matt Spinler475e5742019-07-18 16:09:49 -0500167
Matt Spinler89fa0822019-07-17 13:54:30 -0500168 fs::remove_all(pelFilename.parent_path());
169}
Matt Spinler67456c22019-10-21 12:22:49 -0500170
Matt Spinlere95fd012020-01-07 12:53:16 -0600171TEST_F(ManagerTest, TestCreateWithInvalidPEL)
172{
173 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500174 std::make_unique<MockDataInterface>();
Matt Spinlere95fd012020-01-07 12:53:16 -0600175
176 openpower::pels::Manager manager{
177 logManager, std::move(dataIface),
178 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
179 std::placeholders::_2, std::placeholders::_3)};
180
181 // Create a PEL, write it to a file, and pass that filename into
182 // the create function.
183 auto data = pelDataFactory(TestPELType::pelSimple);
184
185 // Truncate it to make it invalid.
186 data.resize(200);
187
188 fs::path pelFilename = makeTempDir() / "rawpel";
189 std::ofstream pelFile{pelFilename};
190 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
191 pelFile.close();
192
193 std::string adItem = "RAWPEL=" + pelFilename.string();
194 std::vector<std::string> additionalData{adItem};
195 std::vector<std::string> associations;
196
197 manager.create("error message", 42, 0,
198 phosphor::logging::Entry::Level::Error, additionalData,
199 associations);
200
201 // Run the event loop to log the bad PEL event
202 sdeventplus::Event e{sdEvent};
203 e.run(std::chrono::milliseconds(1));
204
205 PEL invalidPEL{data};
206 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.BadHostPEL");
207 EXPECT_EQ(logger.errLevel, phosphor::logging::Entry::Level::Error);
208 EXPECT_EQ(std::stoi(logger.ad["PLID"], nullptr, 16), invalidPEL.plid());
209 EXPECT_EQ(logger.ad["OBMC_LOG_ID"], "42");
210 EXPECT_EQ(logger.ad["SRC"], (*invalidPEL.primarySRC())->asciiString());
211 EXPECT_EQ(logger.ad["PEL_SIZE"], std::to_string(data.size()));
212
Matt Spinlerfe721892020-04-02 10:28:08 -0500213 // Check that the bad PEL data was saved to a file.
214 auto badPELData = readPELFile(getPELRepoPath() / "badPEL");
215 EXPECT_EQ(*badPELData, data);
216
Matt Spinlere95fd012020-01-07 12:53:16 -0600217 fs::remove_all(pelFilename.parent_path());
218}
219
Matt Spinler67456c22019-10-21 12:22:49 -0500220// Test that the message registry can be used to build a PEL.
221TEST_F(ManagerTest, TestCreateWithMessageRegistry)
222{
223 const auto registry = R"(
224{
225 "PELs":
226 [
227 {
228 "Name": "xyz.openbmc_project.Error.Test",
229 "Subsystem": "power_supply",
230 "ActionFlags": ["service_action", "report"],
231 "SRC":
232 {
233 "ReasonCode": "0x2030"
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800234 },
Vijay Lobo593a4c62021-06-16 14:25:26 -0500235 "Callouts": [
236 {
237 "CalloutList": [
238 {"Priority": "high", "Procedure": "bmc_code"},
239 {"Priority": "medium", "SymbolicFRU": "service_docs"}
240 ]
241 }
242 ],
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800243 "Documentation":
244 {
245 "Description": "A PGOOD Fault",
246 "Message": "PS had a PGOOD Fault"
Matt Spinler67456c22019-10-21 12:22:49 -0500247 }
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500248 },
249 {
250 "Name": "xyz.openbmc_project.Logging.Error.Default",
251 "Subsystem": "bmc_firmware",
252 "SRC":
253 {
254 "ReasonCode": "0x2031"
255 },
256 "Documentation":
257 {
258 "Description": "The entry used when no match found",
259 "Message": "This is a generic SRC"
260 }
Matt Spinler67456c22019-10-21 12:22:49 -0500261 }
262 ]
263}
264)";
265
Matt Spinler0d804ef2020-05-12 16:16:26 -0500266 auto path = getPELReadOnlyDataPath();
Matt Spinlerd4ffb652019-11-12 14:16:14 -0600267 fs::create_directories(path);
268 path /= "message_registry.json";
269
Matt Spinler67456c22019-10-21 12:22:49 -0500270 std::ofstream registryFile{path};
271 registryFile << registry;
272 registryFile.close();
273
Matt Spinler67456c22019-10-21 12:22:49 -0500274 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500275 std::make_unique<MockDataInterface>();
Matt Spinler67456c22019-10-21 12:22:49 -0500276
Sumit Kumar9d43a722021-08-24 09:46:19 -0500277 MockDataInterface* mockIface =
278 reinterpret_cast<MockDataInterface*>(dataIface.get());
279
280 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
281 "system/entry"};
282 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType))
283 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
284
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600285 openpower::pels::Manager manager{
286 logManager, std::move(dataIface),
287 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
288 std::placeholders::_2, std::placeholders::_3)};
Matt Spinler67456c22019-10-21 12:22:49 -0500289
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500290 std::vector<std::string> additionalData{"FOO=BAR"};
Matt Spinler67456c22019-10-21 12:22:49 -0500291 std::vector<std::string> associations;
292
293 // Create the event log to create the PEL from.
294 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
295 phosphor::logging::Entry::Level::Error, additionalData,
296 associations);
297
298 // Ensure a PEL was created in the repository
299 auto pelFile = findAnyPELInRepo();
300 ASSERT_TRUE(pelFile);
301
302 auto data = readPELFile(*pelFile);
303 PEL pel(*data);
304
305 // Spot check it. Other testcases cover the details.
306 EXPECT_TRUE(pel.valid());
307 EXPECT_EQ(pel.obmcLogID(), 33);
308 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
309 "BD612030 ");
Vijay Lobod354a392021-06-01 16:21:02 -0500310 // Check if the eventId creation is good
311 EXPECT_EQ(manager.getEventId(pel),
312 "BD612030 00000055 00000010 00000000 00000000 00000000 00000000 "
313 "00000000 00000000");
Vijay Lobo593a4c62021-06-16 14:25:26 -0500314 // Check if resolution property creation is good
315 EXPECT_EQ(manager.getResolution(pel),
Matt Spinlerea2873d2021-08-18 10:35:40 -0500316 "1. Priority: High, Procedure: BMC0001\n2. Priority: Medium, PN: "
Vijay Lobo593a4c62021-06-16 14:25:26 -0500317 "SVCDOCS\n");
Matt Spinler67456c22019-10-21 12:22:49 -0500318
319 // Remove it
320 manager.erase(33);
321 pelFile = findAnyPELInRepo();
322 EXPECT_FALSE(pelFile);
323
324 // Create an event log that can't be found in the registry.
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500325 // In this case, xyz.openbmc_project.Logging.Error.Default will
326 // be used as the key instead to find a registry match.
327 manager.create("xyz.openbmc_project.Error.Foo", 42, 0,
Matt Spinler67456c22019-10-21 12:22:49 -0500328 phosphor::logging::Entry::Level::Error, additionalData,
329 associations);
330
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500331 // Ensure a PEL was still created in the repository
Matt Spinler67456c22019-10-21 12:22:49 -0500332 pelFile = findAnyPELInRepo();
Matt Spinler30ddc9f2020-07-16 15:39:59 -0500333 ASSERT_TRUE(pelFile);
334
335 data = readPELFile(*pelFile);
336 PEL newPEL(*data);
337
338 EXPECT_TRUE(newPEL.valid());
339 EXPECT_EQ(newPEL.obmcLogID(), 42);
340 EXPECT_EQ(newPEL.primarySRC().value()->asciiString(),
341 "BD8D2031 ");
342
343 // Check for both the original AdditionalData item as well as
344 // the ERROR_NAME item that should contain the error message
345 // property that wasn't found.
346 std::string errorName;
347 std::string adItem;
348
349 for (const auto& section : newPEL.optionalSections())
350 {
351 if (SectionID::userData == static_cast<SectionID>(section->header().id))
352 {
353 if (UserDataFormat::json ==
354 static_cast<UserDataFormat>(section->header().subType))
355 {
356 auto ud = static_cast<UserData*>(section.get());
357
358 // Check that there was a UserData section added that
359 // contains debug details about the device.
360 const auto& d = ud->data();
361 std::string jsonString{d.begin(), d.end()};
362 auto json = nlohmann::json::parse(jsonString);
363
364 if (json.contains("ERROR_NAME"))
365 {
366 errorName = json["ERROR_NAME"].get<std::string>();
367 }
368
369 if (json.contains("FOO"))
370 {
371 adItem = json["FOO"].get<std::string>();
372 }
373 }
374 }
375 if (!errorName.empty())
376 {
377 break;
378 }
379 }
380
381 EXPECT_EQ(errorName, "xyz.openbmc_project.Error.Foo");
382 EXPECT_EQ(adItem, "BAR");
Matt Spinler67456c22019-10-21 12:22:49 -0500383}
Matt Spinlera34ab722019-12-16 10:39:32 -0600384
385TEST_F(ManagerTest, TestDBusMethods)
386{
Matt Spinlera34ab722019-12-16 10:39:32 -0600387 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500388 std::make_unique<MockDataInterface>();
Matt Spinlera34ab722019-12-16 10:39:32 -0600389
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600390 Manager manager{logManager, std::move(dataIface),
391 std::bind(std::mem_fn(&TestLogger::log), &logger,
392 std::placeholders::_1, std::placeholders::_2,
393 std::placeholders::_3)};
Matt Spinlera34ab722019-12-16 10:39:32 -0600394
395 // Create a PEL, write it to a file, and pass that filename into
396 // the create function so there's one in the repo.
397 auto data = pelDataFactory(TestPELType::pelSimple);
398
399 fs::path pelFilename = makeTempDir() / "rawpel";
400 std::ofstream pelFile{pelFilename};
401 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
402 pelFile.close();
403
404 std::string adItem = "RAWPEL=" + pelFilename.string();
405 std::vector<std::string> additionalData{adItem};
406 std::vector<std::string> associations;
407
408 manager.create("error message", 42, 0,
409 phosphor::logging::Entry::Level::Error, additionalData,
410 associations);
411
412 // getPELFromOBMCID
413 auto newData = manager.getPELFromOBMCID(42);
414 EXPECT_EQ(newData.size(), data.size());
415
416 // Read the PEL to get the ID for later
417 PEL pel{newData};
418 auto id = pel.id();
419
420 EXPECT_THROW(
421 manager.getPELFromOBMCID(id + 1),
422 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
423
424 // getPEL
425 auto unixfd = manager.getPEL(id);
426
427 // Get the size
428 struct stat s;
429 int r = fstat(unixfd, &s);
430 ASSERT_EQ(r, 0);
431 auto size = s.st_size;
432
433 // Open the FD and check the contents
434 FILE* fp = fdopen(unixfd, "r");
435 ASSERT_NE(fp, nullptr);
436
437 std::vector<uint8_t> fdData;
438 fdData.resize(size);
439 r = fread(fdData.data(), 1, size, fp);
440 EXPECT_EQ(r, size);
441
442 EXPECT_EQ(newData, fdData);
443
444 fclose(fp);
445
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600446 // Run the event loop to close the FD
447 sdeventplus::Event e{sdEvent};
448 e.run(std::chrono::milliseconds(1));
449
Matt Spinlera34ab722019-12-16 10:39:32 -0600450 EXPECT_THROW(
451 manager.getPEL(id + 1),
452 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
453
454 // hostAck
455 manager.hostAck(id);
456
457 EXPECT_THROW(
458 manager.hostAck(id + 1),
459 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
460
461 // hostReject
462 manager.hostReject(id, Manager::RejectionReason::BadPEL);
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600463
464 // Run the event loop to log the bad PEL event
465 e.run(std::chrono::milliseconds(1));
466
467 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.SentBadPELToHost");
468 EXPECT_EQ(id, std::stoi(logger.ad["BAD_ID"], nullptr, 16));
469
Matt Spinlera34ab722019-12-16 10:39:32 -0600470 manager.hostReject(id, Manager::RejectionReason::HostFull);
471
472 EXPECT_THROW(
473 manager.hostReject(id + 1, Manager::RejectionReason::BadPEL),
474 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
475
476 fs::remove_all(pelFilename.parent_path());
Ramesh Iyyarf4203c42021-06-24 06:09:23 -0500477
478 // GetPELIdFromBMCLogId
479 EXPECT_EQ(pel.id(), manager.getPELIdFromBMCLogId(pel.obmcLogID()));
480 EXPECT_THROW(
481 manager.getPELIdFromBMCLogId(pel.obmcLogID() + 1),
482 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ramesh Iyyar530efbf2021-06-24 06:22:22 -0500483
484 // GetBMCLogIdFromPELId
485 EXPECT_EQ(pel.obmcLogID(), manager.getBMCLogIdFromPELId(pel.id()));
486 EXPECT_THROW(
487 manager.getBMCLogIdFromPELId(pel.id() + 1),
488 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Matt Spinlera34ab722019-12-16 10:39:32 -0600489}
Matt Spinler19e72902020-01-24 11:05:20 -0600490
491// An ESEL from the wild
492const std::string esel{
493 "00 00 df 00 00 00 00 20 00 04 12 01 6f aa 00 00 "
494 "50 48 00 30 01 00 33 00 00 00 00 07 5c 69 cc 0d 00 00 00 07 5c d5 50 db "
495 "42 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 90 00 00 4e 90 00 00 4e "
496 "55 48 00 18 01 00 09 00 8a 03 40 00 00 00 00 00 ff ff 00 00 00 00 00 00 "
497 "50 53 00 50 01 01 00 00 02 00 00 09 33 2d 00 48 00 00 00 e0 00 00 10 00 "
498 "00 00 00 00 00 20 00 00 00 0c 00 02 00 00 00 fa 00 00 0c e4 00 00 00 12 "
499 "42 43 38 41 33 33 32 44 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
500 "20 20 20 20 20 20 20 20 55 44 00 1c 01 06 01 00 02 54 41 4b 00 00 00 06 "
501 "00 00 00 55 00 01 f9 20 00 00 00 00 55 44 00 24 01 06 01 00 01 54 41 4b "
502 "00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 23 01 00 02 00 05 00 00 "
503 "55 44 00 0c 01 0b 01 00 0f 01 00 00 55 44 00 10 01 04 01 00 0f 9f de 6a "
504 "00 01 00 00 55 44 00 7c 00 0c 01 00 00 13 0c 02 00 fa 0c e4 16 00 01 2c "
505 "0c 1c 16 00 00 fa 0a f0 14 00 00 fa 0b b8 14 00 00 be 09 60 12 00 01 2c "
506 "0d 7a 12 00 00 fa 0c 4e 10 00 00 fa 0c e4 10 00 00 be 0a 8c 16 00 01 2c "
507 "0c 1c 16 00 01 09 09 f6 16 00 00 fa 09 f6 14 00 00 fa 0b b8 14 00 00 fa "
508 "0a f0 14 00 00 be 08 ca 12 00 01 2c 0c e4 12 00 00 fa 0b 54 10 00 00 fa "
509 "0c 2d 10 00 00 be 08 ca 55 44 00 58 01 03 01 00 00 00 00 00 00 05 31 64 "
510 "00 00 00 00 00 05 0d d4 00 00 00 00 40 5f 06 e0 00 00 00 00 40 5d d2 00 "
511 "00 00 00 00 40 57 d3 d0 00 00 00 00 40 58 f6 a0 00 00 00 00 40 54 c9 34 "
512 "00 00 00 00 40 55 9a 10 00 00 00 00 40 4c 0a 80 00 00 00 00 00 00 27 14 "
513 "55 44 01 84 01 01 01 00 48 6f 73 74 62 6f 6f 74 20 42 75 69 6c 64 20 49 "
514 "44 3a 20 68 6f 73 74 62 6f 6f 74 2d 66 65 63 37 34 64 66 2d 70 30 61 38 "
515 "37 64 63 34 2f 68 62 69 63 6f 72 65 2e 62 69 6e 00 49 42 4d 2d 77 69 74 "
516 "68 65 72 73 70 6f 6f 6e 2d 4f 50 39 2d 76 32 2e 34 2d 39 2e 32 33 34 0a "
517 "09 6f 70 2d 62 75 69 6c 64 2d 38 32 66 34 63 66 30 0a 09 62 75 69 6c 64 "
518 "72 6f 6f 74 2d 32 30 31 39 2e 30 35 2e 32 2d 31 30 2d 67 38 39 35 39 31 "
519 "31 34 0a 09 73 6b 69 62 6f 6f 74 2d 76 36 2e 35 2d 31 38 2d 67 34 37 30 "
520 "66 66 62 35 66 32 39 64 37 0a 09 68 6f 73 74 62 6f 6f 74 2d 66 65 63 37 "
521 "34 64 66 2d 70 30 61 38 37 64 63 34 0a 09 6f 63 63 2d 65 34 35 39 37 61 "
522 "62 0a 09 6c 69 6e 75 78 2d 35 2e 32 2e 31 37 2d 6f 70 65 6e 70 6f 77 65 "
523 "72 31 2d 70 64 64 63 63 30 33 33 0a 09 70 65 74 69 74 62 6f 6f 74 2d 76 "
524 "31 2e 31 30 2e 34 0a 09 6d 61 63 68 69 6e 65 2d 78 6d 6c 2d 63 36 32 32 "
525 "63 62 35 2d 70 37 65 63 61 62 33 64 0a 09 68 6f 73 74 62 6f 6f 74 2d 62 "
526 "69 6e 61 72 69 65 73 2d 36 36 65 39 61 36 30 0a 09 63 61 70 70 2d 75 63 "
527 "6f 64 65 2d 70 39 2d 64 64 32 2d 76 34 0a 09 73 62 65 2d 36 30 33 33 30 "
528 "65 30 0a 09 68 63 6f 64 65 2d 68 77 30 39 32 31 31 39 61 2e 6f 70 6d 73 "
529 "74 0a 00 00 55 44 00 70 01 04 01 00 0f 9f de 6a 00 05 00 00 07 5f 1d f4 "
530 "30 32 43 59 34 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
531 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
532 "0b ac 54 02 59 41 31 39 33 34 36 39 37 30 35 38 00 00 00 00 00 00 05 22 "
533 "a1 58 01 8a 00 58 40 20 17 18 4d 2c 00 00 00 fc 01 a1 00 00 55 44 00 14 "
534 "01 08 01 00 00 00 00 01 00 00 00 5a 00 00 00 05 55 44 03 fc 01 15 31 00 "
535 "01 28 00 42 46 41 50 49 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 f4 "
536 "00 00 00 00 00 00 03 f4 00 00 00 0b 00 00 00 00 00 00 00 3d 2c 9b c2 84 "
537 "00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 09 "
538 "00 00 00 00 00 11 bd 20 00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 "
539 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 00 00 00 01 2c "
540 "00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0c 1c 00 00 00 64 00 00 00 3d "
541 "2c 9b d1 11 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 "
542 "00 00 00 0a 00 00 00 00 00 13 b5 a0 00 00 00 00 00 01 f8 80 00 00 00 00 "
543 "00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 "
544 "00 00 00 be 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0a 8c 00 00 00 64 "
545 "00 00 00 3d 2c 9b df 98 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 "
546 "00 00 00 00 00 00 00 0b 00 00 00 00 00 15 ae 20 00 00 00 00 00 01 f8 80 "
547 "00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 "
548 "00 00 00 00 00 00 00 fa 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0c e4 "
549 "00 00 00 64 00 00 00 3d 2c 9b ea b7 00 00 01 e4 00 48 43 4f fb ed 70 b1 "
550 "00 00 02 01 00 00 00 00 00 00 00 0c 00 00 00 00 00 17 a6 a0 00 00 00 00 "
551 "00 01 f8 80 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 "
552 "00 00 00 12 00 00 00 00 00 00 00 fa 00 00 00 00 00 00 07 d0 00 00 00 00 "
553 "00 00 0c 4e 00 00 00 64 00 00 00 3d 2c 9b f6 27 00 00 01 e4 00 48 43 4f "
554 "fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 0d 00 00 00 00 00 19 9f 20 "
555 "00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 "
556 "00 00 00 00 00 00 00 12 00 00 00 00 00 00 01 2c 00 00 00 00 00 00 07 d0 "
557 "00 00 00 00 00 00 0d 7a 00 00 00 64 00 00 00 3d 2c 9c 05 75 00 00 01 e4 "
558 "00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 0e 00 00 00 00 "
559 "00 1b 97 a0 00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 00 00 00 00 "
560 "00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 be 00 00 00 00 "
561 "00 00 07 d0 00 00 00 00 00 00 09 60 00 00 00 64 00 00 00 3d 2c 9c 11 29 "
562 "00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 00 00 00 0f "
563 "00 00 00 00 00 1d 90 20 00 00 00 00 00 01 f8 80 00 00 00 00 00 00 00 01 "
564 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 fa "
565 "00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0b b8 00 00 00 64 00 00 00 3d "
566 "2c 9c 1c 45 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 00 00 00 00 "
567 "00 00 00 10 00 00 00 00 00 1f 88 a0 00 00 00 00 00 01 f8 80 00 00 00 00 "
568 "00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 00 "
569 "00 00 00 fa 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0a f0 00 00 00 64 "
570 "00 00 00 3d 2c 9c 2b 14 00 00 01 e4 00 48 43 4f fb ed 70 b1 00 00 02 01 "
571 "00 00 00 00 00 00 00 11 00 00 00 00 00 21 81 20 00 00 00 00 00 01 f8 80 "
572 "00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 "
573 "00 00 00 00 00 00 01 2c 00 00 00 00 00 00 07 d0 00 00 00 00 00 00 0c 1c "
574 "00 00 00 64 00 00 00 3d 2d 6d 8f 9e 00 00 01 e4 00 00 43 4f 52 d7 9c 36 "
575 "00 00 04 73 00 00 00 1c 00 00 00 3d 2d 6d 99 ac 00 00 01 e4 00 10 43 4f "
576 "3f f2 02 3d 00 00 05 58 00 00 00 00 02 00 00 01 00 00 00 00 00 00 00 40 "
577 "00 00 00 2c 55 44 00 30 01 15 31 00 01 28 00 42 46 41 50 49 5f 44 42 47 "
578 "00 00 00 00 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 28 00 00 00 00 "
579 "00 00 00 00 55 44 01 74 01 15 31 00 01 28 00 42 46 41 50 49 5f 49 00 00 "
580 "00 00 00 00 00 00 00 00 00 00 01 6c 00 00 00 00 00 00 01 6c 00 00 00 0b "
581 "00 00 00 00 00 00 00 3c 0d 52 18 5e 00 00 01 e4 00 08 43 4f 46 79 94 13 "
582 "00 00 0a 5b 00 00 00 00 00 00 2c 00 00 00 00 24 00 00 00 3c 0d 6b 26 6c "
583 "00 00 01 e4 00 00 43 4f 4e 9b 18 74 00 00 01 03 00 00 00 1c 00 00 00 3c "
584 "12 b9 2d 13 00 00 01 e4 00 00 43 4f ea 31 ed d4 00 00 05 c4 00 00 00 1c "
585 "00 00 00 3c 13 02 73 53 00 00 01 e4 00 00 43 4f ea 31 ed d4 00 00 05 c4 "
586 "00 00 00 1c 00 00 00 3c 13 04 7c 94 00 00 01 e4 00 00 43 4f ea 31 ed d4 "
587 "00 00 05 c4 00 00 00 1c 00 00 00 3c 13 06 ad e1 00 00 01 e4 00 00 43 4f "
588 "ea 31 ed d4 00 00 05 c4 00 00 00 1c 00 00 00 3c 13 07 3f 77 00 00 01 e4 "
589 "00 00 43 4f 5e 4a 55 32 00 00 10 f2 00 00 00 1c 00 00 00 3c 13 07 4e e4 "
590 "00 00 01 e4 00 00 43 4f 5e 4a 55 32 00 00 0d 68 00 00 00 1c 00 00 00 3c "
591 "13 36 79 18 00 00 01 e4 00 00 43 4f ea 31 ed d4 00 00 05 c4 00 00 00 1c "
592 "00 00 00 3d 2c 9c 36 70 00 00 01 e4 00 00 43 4f 23 45 90 97 00 00 02 47 "
593 "00 00 00 1c 00 00 00 3d 2d 6d a3 ed 00 00 01 e4 00 08 43 4f 74 3a 5b 1a "
594 "00 00 04 cc 00 00 00 00 02 00 00 01 00 00 00 24 55 44 00 30 01 15 31 00 "
595 "01 28 00 42 53 43 41 4e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 "
596 "00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 00"};
597
598TEST_F(ManagerTest, TestESELToRawData)
599{
600 auto data = Manager::eselToRawData(esel);
601
602 EXPECT_EQ(data.size(), 2464);
603
604 PEL pel{data};
605 EXPECT_TRUE(pel.valid());
606}
607
608TEST_F(ManagerTest, TestCreateWithESEL)
609{
610 std::unique_ptr<DataInterfaceBase> dataIface =
Matt Spinlere6b48f12020-04-02 09:51:39 -0500611 std::make_unique<MockDataInterface>();
Matt Spinler19e72902020-01-24 11:05:20 -0600612
613 openpower::pels::Manager manager{
614 logManager, std::move(dataIface),
615 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
616 std::placeholders::_2, std::placeholders::_3)};
617
618 {
619 std::string adItem = "ESEL=" + esel;
620 std::vector<std::string> additionalData{adItem};
621 std::vector<std::string> associations;
622
623 manager.create("error message", 37, 0,
624 phosphor::logging::Entry::Level::Error, additionalData,
625 associations);
626
627 auto data = manager.getPELFromOBMCID(37);
628 PEL pel{data};
629 EXPECT_TRUE(pel.valid());
630 }
631
632 // Now an invalid one
633 {
634 std::string adItem = "ESEL=" + esel;
635
636 // Crop it
637 adItem.resize(adItem.size() - 300);
638
639 std::vector<std::string> additionalData{adItem};
640 std::vector<std::string> associations;
641
642 manager.create("error message", 38, 0,
643 phosphor::logging::Entry::Level::Error, additionalData,
644 associations);
645
646 EXPECT_THROW(
647 manager.getPELFromOBMCID(38),
648 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
649
650 // Run the event loop to log the bad PEL event
651 sdeventplus::Event e{sdEvent};
652 e.run(std::chrono::milliseconds(1));
653
654 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.BadHostPEL");
655 EXPECT_EQ(logger.errLevel, phosphor::logging::Entry::Level::Error);
656 }
657}
Matt Spinler7e727a32020-07-07 15:00:17 -0500658
659// Test that PELs will be pruned when necessary
660TEST_F(ManagerTest, TestPruning)
661{
662 sdeventplus::Event e{sdEvent};
663
664 std::unique_ptr<DataInterfaceBase> dataIface =
665 std::make_unique<MockDataInterface>();
666
667 openpower::pels::Manager manager{
668 logManager, std::move(dataIface),
669 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
670 std::placeholders::_2, std::placeholders::_3)};
671
672 // Create 25 1000B (4096B on disk each, which is what is used for pruning)
673 // BMC non-informational PELs in the 100KB repository. After the 24th one,
674 // the repo will be 96% full and a prune should be triggered to remove all
675 // but 7 to get under 30% full. Then when the 25th is added there will be
676 // 8 left.
677
678 auto dir = makeTempDir();
679 for (int i = 1; i <= 25; i++)
680 {
681 auto data = pelFactory(42, 'O', 0x40, 0x8800, 1000);
682
683 fs::path pelFilename = dir / "rawpel";
684 std::ofstream pelFile{pelFilename};
685 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
686 pelFile.close();
687
688 std::string adItem = "RAWPEL=" + pelFilename.string();
689 std::vector<std::string> additionalData{adItem};
690 std::vector<std::string> associations;
691
692 manager.create("error message", 42, 0,
693 phosphor::logging::Entry::Level::Error, additionalData,
694 associations);
695
696 // Simulate the code getting back to the event loop
697 // after each create.
698 e.run(std::chrono::milliseconds(1));
699
700 if (i < 24)
701 {
702 EXPECT_EQ(countPELsInRepo(), i);
703 }
704 else if (i == 24)
705 {
706 // Prune occured
707 EXPECT_EQ(countPELsInRepo(), 7);
708 }
709 else // i == 25
710 {
711 EXPECT_EQ(countPELsInRepo(), 8);
712 }
713 }
714
715 try
716 {
717 // Make sure the 8 newest ones are still found.
718 for (uint32_t i = 0; i < 8; i++)
719 {
720 manager.getPEL(0x50000012 + i);
721 }
722 }
Patrick Williams66491c62021-10-06 12:23:37 -0500723 catch (
724 const sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument&
Matt Spinlerbe952d22022-07-01 11:30:11 -0500725 ex)
Matt Spinler7e727a32020-07-07 15:00:17 -0500726 {
727 ADD_FAILURE() << "PELs should have all been found";
728 }
729
730 fs::remove_all(dir);
731}
Matt Spinlerff9cec22020-07-15 13:06:35 -0500732
733// Test that manually deleting a PEL file will be recognized by the code.
734TEST_F(ManagerTest, TestPELManualDelete)
735{
736 sdeventplus::Event e{sdEvent};
737
738 std::unique_ptr<DataInterfaceBase> dataIface =
739 std::make_unique<MockDataInterface>();
740
741 openpower::pels::Manager manager{
742 logManager, std::move(dataIface),
743 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
744 std::placeholders::_2, std::placeholders::_3)};
745
746 auto data = pelDataFactory(TestPELType::pelSimple);
747 auto dir = makeTempDir();
748 fs::path pelFilename = dir / "rawpel";
749
750 std::string adItem = "RAWPEL=" + pelFilename.string();
751 std::vector<std::string> additionalData{adItem};
752 std::vector<std::string> associations;
753
754 // Add 20 PELs, they will get incrementing IDs like
755 // 0x50000001, 0x50000002, etc.
756 for (int i = 1; i <= 20; i++)
757 {
758 std::ofstream pelFile{pelFilename};
759 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
760 pelFile.close();
761
762 manager.create("error message", 42, 0,
763 phosphor::logging::Entry::Level::Error, additionalData,
764 associations);
765
766 // Sanity check this ID is really there so we can test
767 // it was deleted later. This will throw an exception if
768 // not present.
769 manager.getPEL(0x50000000 + i);
770
771 // Run an event loop pass where the internal FD is deleted
772 // after the getPEL function call.
773 e.run(std::chrono::milliseconds(1));
774 }
775
776 EXPECT_EQ(countPELsInRepo(), 20);
777
778 deletePELFile(0x50000001);
779
780 // Run a single event loop pass so the inotify event can run
781 e.run(std::chrono::milliseconds(1));
782
783 EXPECT_EQ(countPELsInRepo(), 19);
784
785 EXPECT_THROW(
786 manager.getPEL(0x50000001),
787 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
788
789 // Delete a few more, they should all get handled in the same
790 // event loop pass
791 std::vector<uint32_t> toDelete{0x50000002, 0x50000003, 0x50000004,
792 0x50000005, 0x50000006};
793 std::for_each(toDelete.begin(), toDelete.end(),
794 [](auto i) { deletePELFile(i); });
795
796 e.run(std::chrono::milliseconds(1));
797
798 EXPECT_EQ(countPELsInRepo(), 14);
799
800 std::for_each(toDelete.begin(), toDelete.end(), [&manager](const auto i) {
801 EXPECT_THROW(
802 manager.getPEL(i),
803 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
804 });
805
806 fs::remove_all(dir);
807}
808
809// Test that deleting all PELs at once is handled OK.
810TEST_F(ManagerTest, TestPELManualDeleteAll)
811{
812 sdeventplus::Event e{sdEvent};
813
814 std::unique_ptr<DataInterfaceBase> dataIface =
815 std::make_unique<MockDataInterface>();
816
817 openpower::pels::Manager manager{
818 logManager, std::move(dataIface),
819 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
820 std::placeholders::_2, std::placeholders::_3)};
821
822 auto data = pelDataFactory(TestPELType::pelSimple);
823 auto dir = makeTempDir();
824 fs::path pelFilename = dir / "rawpel";
825
826 std::string adItem = "RAWPEL=" + pelFilename.string();
827 std::vector<std::string> additionalData{adItem};
828 std::vector<std::string> associations;
829
830 // Add 200 PELs, they will get incrementing IDs like
831 // 0x50000001, 0x50000002, etc.
832 for (int i = 1; i <= 200; i++)
833 {
834 std::ofstream pelFile{pelFilename};
835 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
836 pelFile.close();
837
838 manager.create("error message", 42, 0,
839 phosphor::logging::Entry::Level::Error, additionalData,
840 associations);
841
842 // Sanity check this ID is really there so we can test
843 // it was deleted later. This will throw an exception if
844 // not present.
845 manager.getPEL(0x50000000 + i);
846
847 // Run an event loop pass where the internal FD is deleted
848 // after the getPEL function call.
849 e.run(std::chrono::milliseconds(1));
850 }
851
852 // Delete them all at once
853 auto logPath = getPELRepoPath() / "logs";
Sumit Kumar1d8835b2021-06-07 09:35:30 -0500854 std::string cmd = "rm " + logPath.string() + "/*_*";
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500855
856 {
857 auto rc = system(cmd.c_str());
858 EXPECT_EQ(rc, 0);
859 }
Matt Spinlerff9cec22020-07-15 13:06:35 -0500860
861 EXPECT_EQ(countPELsInRepo(), 0);
862
863 // It will take 5 event loop passes to process them all
864 for (int i = 0; i < 5; i++)
865 {
866 e.run(std::chrono::milliseconds(1));
867 }
868
869 for (int i = 1; i <= 200; i++)
870 {
871 EXPECT_THROW(
872 manager.getPEL(0x50000000 + i),
873 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
874 }
875
876 fs::remove_all(dir);
877}
Matt Spinler3dd17e92020-08-05 15:04:27 -0500878
879// Test that fault LEDs are turned on when PELs are created
880TEST_F(ManagerTest, TestServiceIndicators)
881{
882 std::unique_ptr<DataInterfaceBase> dataIface =
883 std::make_unique<MockDataInterface>();
884
885 MockDataInterface* mockIface =
886 reinterpret_cast<MockDataInterface*>(dataIface.get());
887
Sumit Kumar9d43a722021-08-24 09:46:19 -0500888 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
889 "system/entry"};
890 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType))
891 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
892
Matt Spinler3dd17e92020-08-05 15:04:27 -0500893 openpower::pels::Manager manager{
894 logManager, std::move(dataIface),
895 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
896 std::placeholders::_2, std::placeholders::_3)};
897
898 // Add a PEL with a callout as if hostboot added it
899 {
900 EXPECT_CALL(*mockIface, getInventoryFromLocCode("U42", 0, true))
901 .WillOnce(Return("/system/chassis/processor"));
902
Matt Spinler993168d2021-04-07 16:05:03 -0500903 EXPECT_CALL(*mockIface,
904 setFunctional("/system/chassis/processor", false))
Matt Spinler3dd17e92020-08-05 15:04:27 -0500905 .Times(1);
906
907 // This hostboot PEL has a single hardware callout in it.
908 auto data = pelFactory(1, 'B', 0x20, 0xA400, 500);
909
910 fs::path pelFilename = makeTempDir() / "rawpel";
911 std::ofstream pelFile{pelFilename};
912 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
913 pelFile.close();
914
915 std::string adItem = "RAWPEL=" + pelFilename.string();
916 std::vector<std::string> additionalData{adItem};
917 std::vector<std::string> associations;
918
919 manager.create("error message", 42, 0,
920 phosphor::logging::Entry::Level::Error, additionalData,
921 associations);
922
923 fs::remove_all(pelFilename.parent_path());
924 }
925
926 // Add a BMC PEL with a callout that uses the message registry
927 {
928 std::vector<std::string> names{"systemA"};
929 EXPECT_CALL(*mockIface, getSystemNames)
930 .Times(1)
Matt Spinler1ab66962020-10-29 13:21:44 -0500931 .WillOnce(Return(names));
Matt Spinler3dd17e92020-08-05 15:04:27 -0500932
933 EXPECT_CALL(*mockIface, expandLocationCode("P42-C23", 0))
934 .WillOnce(Return("U42-P42-C23"));
935
936 // First call to this is when building the Callout section
937 EXPECT_CALL(*mockIface, getInventoryFromLocCode("P42-C23", 0, false))
938 .WillOnce(Return("/system/chassis/processor"));
939
940 // Second call to this is finding the associated LED group
941 EXPECT_CALL(*mockIface, getInventoryFromLocCode("U42-P42-C23", 0, true))
942 .WillOnce(Return("/system/chassis/processor"));
943
Matt Spinler993168d2021-04-07 16:05:03 -0500944 EXPECT_CALL(*mockIface,
945 setFunctional("/system/chassis/processor", false))
Matt Spinler3dd17e92020-08-05 15:04:27 -0500946 .Times(1);
947
948 const auto registry = R"(
949 {
950 "PELs":
951 [
952 {
953 "Name": "xyz.openbmc_project.Error.Test",
954 "Subsystem": "power_supply",
955 "ActionFlags": ["service_action", "report"],
956 "SRC":
957 {
958 "ReasonCode": "0x2030"
959 },
960 "Callouts": [
961 {
962 "CalloutList": [
963 {"Priority": "high", "LocCode": "P42-C23"}
964 ]
965 }
966 ],
967 "Documentation":
968 {
969 "Description": "Test Error",
970 "Message": "Test Error"
971 }
972 }
973 ]
974 })";
975
976 auto path = getPELReadOnlyDataPath();
977 fs::create_directories(path);
978 path /= "message_registry.json";
979
980 std::ofstream registryFile{path};
981 registryFile << registry;
982 registryFile.close();
983
984 std::vector<std::string> additionalData;
985 std::vector<std::string> associations;
986
987 manager.create("xyz.openbmc_project.Error.Test", 42, 0,
988 phosphor::logging::Entry::Level::Error, additionalData,
989 associations);
990 }
991}
Sumit Kumar2ccdcef2021-07-31 10:04:58 -0500992
993// Test for duplicate PELs moved to archive folder
994TEST_F(ManagerTest, TestDuplicatePEL)
995{
996 sdeventplus::Event e{sdEvent};
997 size_t count = 0;
998
999 std::unique_ptr<DataInterfaceBase> dataIface =
1000 std::make_unique<MockDataInterface>();
1001
1002 openpower::pels::Manager manager{
1003 logManager, std::move(dataIface),
1004 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
1005 std::placeholders::_2, std::placeholders::_3)};
1006
1007 for (int i = 0; i < 2; i++)
1008 {
1009 // This hostboot PEL has a single hardware callout in it.
1010 auto data = pelFactory(1, 'B', 0x20, 0xA400, 500);
1011
1012 fs::path pelFilename = makeTempDir() / "rawpel";
1013 std::ofstream pelFile{pelFilename};
1014 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
1015 pelFile.close();
1016
1017 std::string adItem = "RAWPEL=" + pelFilename.string();
1018 std::vector<std::string> additionalData{adItem};
1019 std::vector<std::string> associations;
1020
1021 manager.create("error message", 42, 0,
1022 phosphor::logging::Entry::Level::Error, additionalData,
1023 associations);
1024
1025 e.run(std::chrono::milliseconds(1));
1026 }
1027
1028 for (auto& f :
1029 fs::directory_iterator(getPELRepoPath() / "logs" / "archive"))
1030 {
1031 if (fs::is_regular_file(f.path()))
1032 {
1033 count++;
1034 }
1035 }
1036
1037 // Get count of PELs in the repository & in archive directtory
1038 EXPECT_EQ(countPELsInRepo(), 1);
1039 EXPECT_EQ(count, 1);
1040}
Sumit Kumar3e274432021-09-14 06:37:56 -05001041
1042// Test termination bit set for pel with critical system termination severity
1043TEST_F(ManagerTest, TestTerminateBitWithPELSevCriticalSysTerminate)
1044{
1045 const auto registry = R"(
1046{
1047 "PELs":
1048 [
1049 {
1050 "Name": "xyz.openbmc_project.Error.Test",
1051 "Subsystem": "power_supply",
1052 "Severity": "critical_system_term",
1053 "ActionFlags": ["service_action", "report"],
1054 "SRC":
1055 {
1056 "ReasonCode": "0x2030"
1057 },
1058 "Documentation":
1059 {
1060 "Description": "A PGOOD Fault",
1061 "Message": "PS had a PGOOD Fault"
1062 }
1063 }
1064 ]
1065}
1066)";
1067
1068 auto path = getPELReadOnlyDataPath();
1069 fs::create_directories(path);
1070 path /= "message_registry.json";
1071
1072 std::ofstream registryFile{path};
1073 registryFile << registry;
1074 registryFile.close();
1075
1076 std::unique_ptr<DataInterfaceBase> dataIface =
1077 std::make_unique<MockDataInterface>();
1078
1079 MockDataInterface* mockIface =
1080 reinterpret_cast<MockDataInterface*>(dataIface.get());
1081
1082 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1083 "system/entry"};
1084 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType))
1085 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
1086
1087 openpower::pels::Manager manager{
1088 logManager, std::move(dataIface),
1089 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1,
1090 std::placeholders::_2, std::placeholders::_3)};
1091
1092 std::vector<std::string> additionalData{"FOO=BAR"};
1093 std::vector<std::string> associations;
1094
1095 // Create the event log to create the PEL from.
1096 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
1097 phosphor::logging::Entry::Level::Error, additionalData,
1098 associations);
1099
1100 // Ensure a PEL was created in the repository
1101 auto pelData = findAnyPELInRepo();
1102 ASSERT_TRUE(pelData);
1103
1104 auto getPELData = readPELFile(*pelData);
1105 PEL pel(*getPELData);
1106
1107 // Spot check it. Other testcases cover the details.
1108 EXPECT_TRUE(pel.valid());
1109
1110 // Check for terminate bit set
1111 auto& hexwords = pel.primarySRC().value()->hexwordData();
1112 EXPECT_EQ(hexwords[3] & 0x20000000, 0x20000000);
1113}
Matt Spinler0003af12022-06-08 10:46:17 -05001114
1115TEST_F(ManagerTest, TestSanitizeFieldforDBus)
1116{
1117 std::string base{"(test0!}\n\t ~"};
1118 auto string = base;
1119 string += char{' ' - 1};
1120 string += char{'~' + 1};
1121 string += char{0};
1122 string += char{static_cast<char>(0xFF)};
1123
1124 // convert the last four chars to spaces
1125 EXPECT_EQ(Manager::sanitizeFieldForDBus(string), base + " ");
1126}