1 /** 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 */ 16 #include "extensions/openpower-pels/manager.hpp" 17 #include "log_manager.hpp" 18 #include "mocks.hpp" 19 #include "pel_utils.hpp" 20 21 #include <sdbusplus/test/sdbus_mock.hpp> 22 #include <xyz/openbmc_project/Common/error.hpp> 23 24 #include <fstream> 25 #include <regex> 26 27 #include <gtest/gtest.h> 28 29 using namespace openpower::pels; 30 namespace fs = std::filesystem; 31 32 using ::testing::NiceMock; 33 using ::testing::Return; 34 35 class 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 51 class ManagerTest : public CleanPELFiles 52 { 53 public: 54 ManagerTest() : 55 bus(sdbusplus::get_mocked_new(&sdbusInterface)), 56 logManager(bus, "logging_path") 57 { 58 sd_event_default(&sdEvent); 59 } 60 61 fs::path makeTempDir() 62 { 63 char path[] = "/tmp/tempnameXXXXXX"; 64 std::filesystem::path dir = mkdtemp(path); 65 dirsToRemove.push_back(dir); 66 return dir; 67 } 68 69 ~ManagerTest() 70 { 71 for (const auto& d : dirsToRemove) 72 { 73 std::filesystem::remove_all(d); 74 } 75 sd_event_unref(sdEvent); 76 } 77 78 NiceMock<sdbusplus::SdBusMock> sdbusInterface; 79 sdbusplus::bus_t bus; 80 phosphor::logging::internal::Manager logManager; 81 sd_event* sdEvent; 82 TestLogger logger; 83 std::vector<std::filesystem::path> dirsToRemove; 84 }; 85 86 std::optional<fs::path> findAnyPELInRepo() 87 { 88 // PELs are named <timestamp>_<ID> 89 std::regex expr{"\\d+_\\d+"}; 90 91 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs")) 92 { 93 if (std::regex_search(f.path().string(), expr)) 94 { 95 return f.path(); 96 } 97 } 98 return std::nullopt; 99 } 100 101 size_t countPELsInRepo() 102 { 103 size_t count = 0; 104 std::regex expr{"\\d+_\\d+"}; 105 106 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs")) 107 { 108 if (std::regex_search(f.path().string(), expr)) 109 { 110 count++; 111 } 112 } 113 return count; 114 } 115 116 void deletePELFile(uint32_t id) 117 { 118 char search[20]; 119 120 sprintf(search, "\\d+_%.8X", id); 121 std::regex expr{search}; 122 123 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs")) 124 { 125 if (std::regex_search(f.path().string(), expr)) 126 { 127 fs::remove(f.path()); 128 break; 129 } 130 } 131 } 132 133 // Test that using the RAWPEL=<file> with the Manager::create() call gets 134 // a PEL saved in the repository. 135 TEST_F(ManagerTest, TestCreateWithPEL) 136 { 137 std::unique_ptr<DataInterfaceBase> dataIface = 138 std::make_unique<MockDataInterface>(); 139 140 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 141 142 openpower::pels::Manager manager{ 143 logManager, std::move(dataIface), 144 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 145 std::placeholders::_2, std::placeholders::_3), 146 std::move(journal)}; 147 148 // Create a PEL, write it to a file, and pass that filename into 149 // the create function. 150 auto data = pelDataFactory(TestPELType::pelSimple); 151 152 fs::path pelFilename = makeTempDir() / "rawpel"; 153 std::ofstream pelFile{pelFilename}; 154 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 155 pelFile.close(); 156 157 std::string adItem = "RAWPEL=" + pelFilename.string(); 158 std::vector<std::string> additionalData{adItem}; 159 std::vector<std::string> associations; 160 161 manager.create("error message", 42, 0, 162 phosphor::logging::Entry::Level::Error, additionalData, 163 associations); 164 165 // Find the file in the PEL repository directory 166 auto pelPathInRepo = findAnyPELInRepo(); 167 168 EXPECT_TRUE(pelPathInRepo); 169 170 // Now remove it based on its OpenBMC event log ID 171 manager.erase(42); 172 173 pelPathInRepo = findAnyPELInRepo(); 174 175 EXPECT_FALSE(pelPathInRepo); 176 } 177 178 TEST_F(ManagerTest, TestCreateWithInvalidPEL) 179 { 180 std::unique_ptr<DataInterfaceBase> dataIface = 181 std::make_unique<MockDataInterface>(); 182 183 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 184 185 openpower::pels::Manager manager{ 186 logManager, std::move(dataIface), 187 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 188 std::placeholders::_2, std::placeholders::_3), 189 std::move(journal)}; 190 191 // Create a PEL, write it to a file, and pass that filename into 192 // the create function. 193 auto data = pelDataFactory(TestPELType::pelSimple); 194 195 // Truncate it to make it invalid. 196 data.resize(200); 197 198 fs::path pelFilename = makeTempDir() / "rawpel"; 199 std::ofstream pelFile{pelFilename}; 200 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 201 pelFile.close(); 202 203 std::string adItem = "RAWPEL=" + pelFilename.string(); 204 std::vector<std::string> additionalData{adItem}; 205 std::vector<std::string> associations; 206 207 manager.create("error message", 42, 0, 208 phosphor::logging::Entry::Level::Error, additionalData, 209 associations); 210 211 // Run the event loop to log the bad PEL event 212 sdeventplus::Event e{sdEvent}; 213 e.run(std::chrono::milliseconds(1)); 214 215 PEL invalidPEL{data}; 216 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.BadHostPEL"); 217 EXPECT_EQ(logger.errLevel, phosphor::logging::Entry::Level::Error); 218 EXPECT_EQ(std::stoi(logger.ad["PLID"], nullptr, 16), invalidPEL.plid()); 219 EXPECT_EQ(logger.ad["OBMC_LOG_ID"], "42"); 220 EXPECT_EQ(logger.ad["SRC"], (*invalidPEL.primarySRC())->asciiString()); 221 EXPECT_EQ(logger.ad["PEL_SIZE"], std::to_string(data.size())); 222 223 // Check that the bad PEL data was saved to a file. 224 auto badPELData = readPELFile(getPELRepoPath() / "badPEL"); 225 EXPECT_EQ(*badPELData, data); 226 } 227 228 // Test that the message registry can be used to build a PEL. 229 TEST_F(ManagerTest, TestCreateWithMessageRegistry) 230 { 231 const auto registry = R"( 232 { 233 "PELs": 234 [ 235 { 236 "Name": "xyz.openbmc_project.Error.Test", 237 "Subsystem": "power_supply", 238 "ActionFlags": ["service_action", "report"], 239 "SRC": 240 { 241 "ReasonCode": "0x2030" 242 }, 243 "Callouts": [ 244 { 245 "CalloutList": [ 246 {"Priority": "high", "Procedure": "bmc_code"}, 247 {"Priority": "medium", "SymbolicFRU": "service_docs"} 248 ] 249 } 250 ], 251 "Documentation": 252 { 253 "Description": "A PGOOD Fault", 254 "Message": "PS had a PGOOD Fault" 255 } 256 }, 257 { 258 "Name": "xyz.openbmc_project.Logging.Error.Default", 259 "Subsystem": "bmc_firmware", 260 "SRC": 261 { 262 "ReasonCode": "0x2031" 263 }, 264 "Documentation": 265 { 266 "Description": "The entry used when no match found", 267 "Message": "This is a generic SRC" 268 } 269 } 270 ] 271 } 272 )"; 273 274 auto path = getPELReadOnlyDataPath(); 275 fs::create_directories(path); 276 path /= "message_registry.json"; 277 278 std::ofstream registryFile{path}; 279 registryFile << registry; 280 registryFile.close(); 281 282 std::unique_ptr<DataInterfaceBase> dataIface = 283 std::make_unique<MockDataInterface>(); 284 285 MockDataInterface* mockIface = 286 reinterpret_cast<MockDataInterface*>(dataIface.get()); 287 288 std::vector<std::string> dumpType{"bmc/entry", "resource/entry", 289 "system/entry"}; 290 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType)) 291 .WillRepeatedly(Return(std::vector<bool>{false, false, false})); 292 293 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 294 295 openpower::pels::Manager manager{ 296 logManager, std::move(dataIface), 297 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 298 std::placeholders::_2, std::placeholders::_3), 299 std::move(journal)}; 300 301 std::vector<std::string> additionalData{"FOO=BAR"}; 302 std::vector<std::string> associations; 303 304 // Create the event log to create the PEL from. 305 manager.create("xyz.openbmc_project.Error.Test", 33, 0, 306 phosphor::logging::Entry::Level::Error, additionalData, 307 associations); 308 309 // Ensure a PEL was created in the repository 310 auto pelFile = findAnyPELInRepo(); 311 ASSERT_TRUE(pelFile); 312 313 auto data = readPELFile(*pelFile); 314 PEL pel(*data); 315 316 // Spot check it. Other testcases cover the details. 317 EXPECT_TRUE(pel.valid()); 318 EXPECT_EQ(pel.obmcLogID(), 33); 319 EXPECT_EQ(pel.primarySRC().value()->asciiString(), 320 "BD612030 "); 321 // Check if the eventId creation is good 322 EXPECT_EQ(manager.getEventId(pel), 323 "BD612030 00000055 00000010 00000000 00000000 00000000 00000000 " 324 "00000000 00000000"); 325 // Check if resolution property creation is good 326 EXPECT_EQ(manager.getResolution(pel), 327 "1. Priority: High, Procedure: BMC0001\n2. Priority: Medium, PN: " 328 "SVCDOCS\n"); 329 330 // Remove it 331 manager.erase(33); 332 pelFile = findAnyPELInRepo(); 333 EXPECT_FALSE(pelFile); 334 335 // Create an event log that can't be found in the registry. 336 // In this case, xyz.openbmc_project.Logging.Error.Default will 337 // be used as the key instead to find a registry match. 338 manager.create("xyz.openbmc_project.Error.Foo", 42, 0, 339 phosphor::logging::Entry::Level::Error, additionalData, 340 associations); 341 342 // Ensure a PEL was still created in the repository 343 pelFile = findAnyPELInRepo(); 344 ASSERT_TRUE(pelFile); 345 346 data = readPELFile(*pelFile); 347 PEL newPEL(*data); 348 349 EXPECT_TRUE(newPEL.valid()); 350 EXPECT_EQ(newPEL.obmcLogID(), 42); 351 EXPECT_EQ(newPEL.primarySRC().value()->asciiString(), 352 "BD8D2031 "); 353 354 // Check for both the original AdditionalData item as well as 355 // the ERROR_NAME item that should contain the error message 356 // property that wasn't found. 357 std::string errorName; 358 std::string adItem; 359 360 for (const auto& section : newPEL.optionalSections()) 361 { 362 if (SectionID::userData == static_cast<SectionID>(section->header().id)) 363 { 364 if (UserDataFormat::json == 365 static_cast<UserDataFormat>(section->header().subType)) 366 { 367 auto ud = static_cast<UserData*>(section.get()); 368 369 // Check that there was a UserData section added that 370 // contains debug details about the device. 371 const auto& d = ud->data(); 372 std::string jsonString{d.begin(), d.end()}; 373 auto json = nlohmann::json::parse(jsonString); 374 375 if (json.contains("ERROR_NAME")) 376 { 377 errorName = json["ERROR_NAME"].get<std::string>(); 378 } 379 380 if (json.contains("FOO")) 381 { 382 adItem = json["FOO"].get<std::string>(); 383 } 384 } 385 } 386 if (!errorName.empty()) 387 { 388 break; 389 } 390 } 391 392 EXPECT_EQ(errorName, "xyz.openbmc_project.Error.Foo"); 393 EXPECT_EQ(adItem, "BAR"); 394 } 395 396 TEST_F(ManagerTest, TestDBusMethods) 397 { 398 std::unique_ptr<DataInterfaceBase> dataIface = 399 std::make_unique<MockDataInterface>(); 400 401 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 402 403 Manager manager{logManager, std::move(dataIface), 404 std::bind(std::mem_fn(&TestLogger::log), &logger, 405 std::placeholders::_1, std::placeholders::_2, 406 std::placeholders::_3), 407 std::move(journal)}; 408 409 // Create a PEL, write it to a file, and pass that filename into 410 // the create function so there's one in the repo. 411 auto data = pelDataFactory(TestPELType::pelSimple); 412 413 fs::path pelFilename = makeTempDir() / "rawpel"; 414 std::ofstream pelFile{pelFilename}; 415 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 416 pelFile.close(); 417 418 std::string adItem = "RAWPEL=" + pelFilename.string(); 419 std::vector<std::string> additionalData{adItem}; 420 std::vector<std::string> associations; 421 422 manager.create("error message", 42, 0, 423 phosphor::logging::Entry::Level::Error, additionalData, 424 associations); 425 426 // getPELFromOBMCID 427 auto newData = manager.getPELFromOBMCID(42); 428 EXPECT_EQ(newData.size(), data.size()); 429 430 // Read the PEL to get the ID for later 431 PEL pel{newData}; 432 auto id = pel.id(); 433 434 EXPECT_THROW( 435 manager.getPELFromOBMCID(id + 1), 436 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 437 438 // getPEL 439 auto unixfd = manager.getPEL(id); 440 441 // Get the size 442 struct stat s; 443 int r = fstat(unixfd, &s); 444 ASSERT_EQ(r, 0); 445 auto size = s.st_size; 446 447 // Open the FD and check the contents 448 FILE* fp = fdopen(unixfd, "r"); 449 ASSERT_NE(fp, nullptr); 450 451 std::vector<uint8_t> fdData; 452 fdData.resize(size); 453 r = fread(fdData.data(), 1, size, fp); 454 EXPECT_EQ(r, size); 455 456 EXPECT_EQ(newData, fdData); 457 458 fclose(fp); 459 460 // Run the event loop to close the FD 461 sdeventplus::Event e{sdEvent}; 462 e.run(std::chrono::milliseconds(1)); 463 464 EXPECT_THROW( 465 manager.getPEL(id + 1), 466 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 467 468 // hostAck 469 manager.hostAck(id); 470 471 EXPECT_THROW( 472 manager.hostAck(id + 1), 473 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 474 475 // hostReject 476 manager.hostReject(id, Manager::RejectionReason::BadPEL); 477 478 // Run the event loop to log the bad PEL event 479 e.run(std::chrono::milliseconds(1)); 480 481 EXPECT_EQ(logger.errName, "org.open_power.Logging.Error.SentBadPELToHost"); 482 EXPECT_EQ(id, std::stoi(logger.ad["BAD_ID"], nullptr, 16)); 483 484 manager.hostReject(id, Manager::RejectionReason::HostFull); 485 486 EXPECT_THROW( 487 manager.hostReject(id + 1, Manager::RejectionReason::BadPEL), 488 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 489 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); 495 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); 501 } 502 503 // An ESEL from the wild 504 const 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 20 23 05 11 10 20 20 00 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 610 TEST_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 620 TEST_F(ManagerTest, TestCreateWithESEL) 621 { 622 std::unique_ptr<DataInterfaceBase> dataIface = 623 std::make_unique<MockDataInterface>(); 624 625 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 626 627 openpower::pels::Manager manager{ 628 logManager, std::move(dataIface), 629 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 630 std::placeholders::_2, std::placeholders::_3), 631 std::move(journal)}; 632 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 } 673 674 // Test that PELs will be pruned when necessary 675 TEST_F(ManagerTest, TestPruning) 676 { 677 sdeventplus::Event e{sdEvent}; 678 679 std::unique_ptr<DataInterfaceBase> dataIface = 680 std::make_unique<MockDataInterface>(); 681 682 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 683 684 openpower::pels::Manager manager{ 685 logManager, std::move(dataIface), 686 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 687 std::placeholders::_2, std::placeholders::_3), 688 std::move(journal)}; 689 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 } 741 catch ( 742 const sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument& 743 ex) 744 { 745 ADD_FAILURE() << "PELs should have all been found"; 746 } 747 } 748 749 // Test that manually deleting a PEL file will be recognized by the code. 750 TEST_F(ManagerTest, TestPELManualDelete) 751 { 752 sdeventplus::Event e{sdEvent}; 753 754 std::unique_ptr<DataInterfaceBase> dataIface = 755 std::make_unique<MockDataInterface>(); 756 757 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 758 759 openpower::pels::Manager manager{ 760 logManager, std::move(dataIface), 761 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 762 std::placeholders::_2, std::placeholders::_3), 763 std::move(journal)}; 764 765 auto data = pelDataFactory(TestPELType::pelSimple); 766 auto dir = makeTempDir(); 767 fs::path pelFilename = dir / "rawpel"; 768 769 std::string adItem = "RAWPEL=" + pelFilename.string(); 770 std::vector<std::string> additionalData{adItem}; 771 std::vector<std::string> associations; 772 773 // Add 20 PELs, they will get incrementing IDs like 774 // 0x50000001, 0x50000002, etc. 775 for (int i = 1; i <= 20; i++) 776 { 777 std::ofstream pelFile{pelFilename}; 778 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 779 pelFile.close(); 780 781 manager.create("error message", 42, 0, 782 phosphor::logging::Entry::Level::Error, additionalData, 783 associations); 784 785 // Sanity check this ID is really there so we can test 786 // it was deleted later. This will throw an exception if 787 // not present. 788 manager.getPEL(0x50000000 + i); 789 790 // Run an event loop pass where the internal FD is deleted 791 // after the getPEL function call. 792 e.run(std::chrono::milliseconds(1)); 793 } 794 795 EXPECT_EQ(countPELsInRepo(), 20); 796 797 deletePELFile(0x50000001); 798 799 // Run a single event loop pass so the inotify event can run 800 e.run(std::chrono::milliseconds(1)); 801 802 EXPECT_EQ(countPELsInRepo(), 19); 803 804 EXPECT_THROW( 805 manager.getPEL(0x50000001), 806 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 807 808 // Delete a few more, they should all get handled in the same 809 // event loop pass 810 std::vector<uint32_t> toDelete{0x50000002, 0x50000003, 0x50000004, 811 0x50000005, 0x50000006}; 812 std::for_each(toDelete.begin(), toDelete.end(), 813 [](auto i) { deletePELFile(i); }); 814 815 e.run(std::chrono::milliseconds(1)); 816 817 EXPECT_EQ(countPELsInRepo(), 14); 818 819 std::for_each(toDelete.begin(), toDelete.end(), [&manager](const auto i) { 820 EXPECT_THROW( 821 manager.getPEL(i), 822 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 823 }); 824 } 825 826 // Test that deleting all PELs at once is handled OK. 827 TEST_F(ManagerTest, TestPELManualDeleteAll) 828 { 829 sdeventplus::Event e{sdEvent}; 830 831 std::unique_ptr<DataInterfaceBase> dataIface = 832 std::make_unique<MockDataInterface>(); 833 834 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 835 836 openpower::pels::Manager manager{ 837 logManager, std::move(dataIface), 838 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 839 std::placeholders::_2, std::placeholders::_3), 840 std::move(journal)}; 841 842 auto data = pelDataFactory(TestPELType::pelSimple); 843 auto dir = makeTempDir(); 844 fs::path pelFilename = dir / "rawpel"; 845 846 std::string adItem = "RAWPEL=" + pelFilename.string(); 847 std::vector<std::string> additionalData{adItem}; 848 std::vector<std::string> associations; 849 850 // Add 200 PELs, they will get incrementing IDs like 851 // 0x50000001, 0x50000002, etc. 852 for (int i = 1; i <= 200; i++) 853 { 854 std::ofstream pelFile{pelFilename}; 855 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 856 pelFile.close(); 857 858 manager.create("error message", 42, 0, 859 phosphor::logging::Entry::Level::Error, additionalData, 860 associations); 861 862 // Sanity check this ID is really there so we can test 863 // it was deleted later. This will throw an exception if 864 // not present. 865 manager.getPEL(0x50000000 + i); 866 867 // Run an event loop pass where the internal FD is deleted 868 // after the getPEL function call. 869 e.run(std::chrono::milliseconds(1)); 870 } 871 872 // Delete them all at once 873 auto logPath = getPELRepoPath() / "logs"; 874 std::string cmd = "rm " + logPath.string() + "/*_*"; 875 876 { 877 auto rc = system(cmd.c_str()); 878 EXPECT_EQ(rc, 0); 879 } 880 881 EXPECT_EQ(countPELsInRepo(), 0); 882 883 // It will take 5 event loop passes to process them all 884 for (int i = 0; i < 5; i++) 885 { 886 e.run(std::chrono::milliseconds(1)); 887 } 888 889 for (int i = 1; i <= 200; i++) 890 { 891 EXPECT_THROW( 892 manager.getPEL(0x50000000 + i), 893 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument); 894 } 895 } 896 897 // Test that fault LEDs are turned on when PELs are created 898 TEST_F(ManagerTest, TestServiceIndicators) 899 { 900 std::unique_ptr<DataInterfaceBase> dataIface = 901 std::make_unique<MockDataInterface>(); 902 903 MockDataInterface* mockIface = 904 reinterpret_cast<MockDataInterface*>(dataIface.get()); 905 906 std::vector<std::string> dumpType{"bmc/entry", "resource/entry", 907 "system/entry"}; 908 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType)) 909 .WillRepeatedly(Return(std::vector<bool>{false, false, false})); 910 911 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 912 913 openpower::pels::Manager manager{ 914 logManager, std::move(dataIface), 915 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 916 std::placeholders::_2, std::placeholders::_3), 917 std::move(journal)}; 918 919 // Add a PEL with a callout as if hostboot added it 920 { 921 EXPECT_CALL(*mockIface, getInventoryFromLocCode("U42", 0, true)) 922 .WillOnce( 923 Return(std::vector<std::string>{"/system/chassis/processor"})); 924 925 EXPECT_CALL(*mockIface, 926 setFunctional("/system/chassis/processor", false)) 927 .Times(1); 928 929 // This hostboot PEL has a single hardware callout in it. 930 auto data = pelFactory(1, 'B', 0x20, 0xA400, 500); 931 932 fs::path pelFilename = makeTempDir() / "rawpel"; 933 std::ofstream pelFile{pelFilename}; 934 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 935 pelFile.close(); 936 937 std::string adItem = "RAWPEL=" + pelFilename.string(); 938 std::vector<std::string> additionalData{adItem}; 939 std::vector<std::string> associations; 940 941 manager.create("error message", 42, 0, 942 phosphor::logging::Entry::Level::Error, additionalData, 943 associations); 944 } 945 946 // Add a BMC PEL with a callout that uses the message registry 947 { 948 std::vector<std::string> names{"systemA"}; 949 EXPECT_CALL(*mockIface, getSystemNames) 950 .Times(1) 951 .WillOnce(Return(names)); 952 953 EXPECT_CALL(*mockIface, expandLocationCode("P42-C23", 0)) 954 .WillOnce(Return("U42-P42-C23")); 955 956 // First call to this is when building the Callout section 957 EXPECT_CALL(*mockIface, getInventoryFromLocCode("P42-C23", 0, false)) 958 .WillOnce( 959 Return(std::vector<std::string>{"/system/chassis/processor"})); 960 961 // Second call to this is finding the associated LED group 962 EXPECT_CALL(*mockIface, getInventoryFromLocCode("U42-P42-C23", 0, true)) 963 .WillOnce( 964 Return(std::vector<std::string>{"/system/chassis/processor"})); 965 966 EXPECT_CALL(*mockIface, 967 setFunctional("/system/chassis/processor", false)) 968 .Times(1); 969 970 const auto registry = R"( 971 { 972 "PELs": 973 [ 974 { 975 "Name": "xyz.openbmc_project.Error.Test", 976 "Subsystem": "power_supply", 977 "ActionFlags": ["service_action", "report"], 978 "SRC": 979 { 980 "ReasonCode": "0x2030" 981 }, 982 "Callouts": [ 983 { 984 "CalloutList": [ 985 {"Priority": "high", "LocCode": "P42-C23"} 986 ] 987 } 988 ], 989 "Documentation": 990 { 991 "Description": "Test Error", 992 "Message": "Test Error" 993 } 994 } 995 ] 996 })"; 997 998 auto path = getPELReadOnlyDataPath(); 999 fs::create_directories(path); 1000 path /= "message_registry.json"; 1001 1002 std::ofstream registryFile{path}; 1003 registryFile << registry; 1004 registryFile.close(); 1005 1006 std::vector<std::string> additionalData; 1007 std::vector<std::string> associations; 1008 1009 manager.create("xyz.openbmc_project.Error.Test", 42, 0, 1010 phosphor::logging::Entry::Level::Error, additionalData, 1011 associations); 1012 } 1013 } 1014 1015 // Test for duplicate PELs moved to archive folder 1016 TEST_F(ManagerTest, TestDuplicatePEL) 1017 { 1018 sdeventplus::Event e{sdEvent}; 1019 size_t count = 0; 1020 1021 std::unique_ptr<DataInterfaceBase> dataIface = 1022 std::make_unique<MockDataInterface>(); 1023 1024 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 1025 1026 openpower::pels::Manager manager{ 1027 logManager, std::move(dataIface), 1028 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 1029 std::placeholders::_2, std::placeholders::_3), 1030 std::move(journal)}; 1031 1032 for (int i = 0; i < 2; i++) 1033 { 1034 // This hostboot PEL has a single hardware callout in it. 1035 auto data = pelFactory(1, 'B', 0x20, 0xA400, 500); 1036 1037 fs::path pelFilename = makeTempDir() / "rawpel"; 1038 std::ofstream pelFile{pelFilename}; 1039 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size()); 1040 pelFile.close(); 1041 1042 std::string adItem = "RAWPEL=" + pelFilename.string(); 1043 std::vector<std::string> additionalData{adItem}; 1044 std::vector<std::string> associations; 1045 1046 manager.create("error message", 42, 0, 1047 phosphor::logging::Entry::Level::Error, additionalData, 1048 associations); 1049 1050 e.run(std::chrono::milliseconds(1)); 1051 } 1052 1053 for (auto& f : 1054 fs::directory_iterator(getPELRepoPath() / "logs" / "archive")) 1055 { 1056 if (fs::is_regular_file(f.path())) 1057 { 1058 count++; 1059 } 1060 } 1061 1062 // Get count of PELs in the repository & in archive directtory 1063 EXPECT_EQ(countPELsInRepo(), 1); 1064 EXPECT_EQ(count, 1); 1065 } 1066 1067 // Test termination bit set for pel with critical system termination severity 1068 TEST_F(ManagerTest, TestTerminateBitWithPELSevCriticalSysTerminate) 1069 { 1070 const auto registry = R"( 1071 { 1072 "PELs": 1073 [ 1074 { 1075 "Name": "xyz.openbmc_project.Error.Test", 1076 "Subsystem": "power_supply", 1077 "Severity": "critical_system_term", 1078 "ActionFlags": ["service_action", "report"], 1079 "SRC": 1080 { 1081 "ReasonCode": "0x2030" 1082 }, 1083 "Documentation": 1084 { 1085 "Description": "A PGOOD Fault", 1086 "Message": "PS had a PGOOD Fault" 1087 } 1088 } 1089 ] 1090 } 1091 )"; 1092 1093 auto path = getPELReadOnlyDataPath(); 1094 fs::create_directories(path); 1095 path /= "message_registry.json"; 1096 1097 std::ofstream registryFile{path}; 1098 registryFile << registry; 1099 registryFile.close(); 1100 1101 std::unique_ptr<DataInterfaceBase> dataIface = 1102 std::make_unique<MockDataInterface>(); 1103 1104 MockDataInterface* mockIface = 1105 reinterpret_cast<MockDataInterface*>(dataIface.get()); 1106 1107 std::vector<std::string> dumpType{"bmc/entry", "resource/entry", 1108 "system/entry"}; 1109 EXPECT_CALL(*mockIface, checkDumpStatus(dumpType)) 1110 .WillRepeatedly(Return(std::vector<bool>{false, false, false})); 1111 1112 std::unique_ptr<JournalBase> journal = std::make_unique<MockJournal>(); 1113 1114 openpower::pels::Manager manager{ 1115 logManager, std::move(dataIface), 1116 std::bind(std::mem_fn(&TestLogger::log), &logger, std::placeholders::_1, 1117 std::placeholders::_2, std::placeholders::_3), 1118 std::move(journal)}; 1119 1120 std::vector<std::string> additionalData{"FOO=BAR"}; 1121 std::vector<std::string> associations; 1122 1123 // Create the event log to create the PEL from. 1124 manager.create("xyz.openbmc_project.Error.Test", 33, 0, 1125 phosphor::logging::Entry::Level::Error, additionalData, 1126 associations); 1127 1128 // Ensure a PEL was created in the repository 1129 auto pelData = findAnyPELInRepo(); 1130 ASSERT_TRUE(pelData); 1131 1132 auto getPELData = readPELFile(*pelData); 1133 PEL pel(*getPELData); 1134 1135 // Spot check it. Other testcases cover the details. 1136 EXPECT_TRUE(pel.valid()); 1137 1138 // Check for terminate bit set 1139 auto& hexwords = pel.primarySRC().value()->hexwordData(); 1140 EXPECT_EQ(hexwords[3] & 0x20000000, 0x20000000); 1141 } 1142 1143 TEST_F(ManagerTest, TestSanitizeFieldforDBus) 1144 { 1145 std::string base{"(test0!}\n\t ~"}; 1146 auto string = base; 1147 string += char{' ' - 1}; 1148 string += char{'~' + 1}; 1149 string += char{0}; 1150 string += char{static_cast<char>(0xFF)}; 1151 1152 // convert the last four chars to spaces 1153 EXPECT_EQ(Manager::sanitizeFieldForDBus(string), base + " "); 1154 } 1155