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/paths.hpp" 17 #include "extensions/openpower-pels/repository.hpp" 18 #include "pel_utils.hpp" 19 20 #include <ext/stdio_filebuf.h> 21 22 #include <filesystem> 23 24 #include <gtest/gtest.h> 25 26 using namespace openpower::pels; 27 namespace fs = std::filesystem; 28 29 /** 30 * Clean the Repo after every testcase. 31 * And because we have PEL object, also clean up 32 * the log ID. 33 */ 34 class RepositoryTest : public CleanLogID 35 { 36 protected: 37 void SetUp() override 38 { 39 repoPath = getPELRepoPath(); 40 } 41 42 void TearDown() override 43 { 44 fs::remove_all(repoPath); 45 } 46 47 fs::path repoPath; 48 }; 49 50 TEST_F(RepositoryTest, FilenameTest) 51 { 52 BCDTime date = {0x20, 0x30, 0x11, 0x28, 0x13, 0x6, 0x7, 0x8}; 53 54 EXPECT_EQ(Repository::getPELFilename(0x12345678, date), 55 "2030112813060708_12345678"); 56 57 EXPECT_EQ(Repository::getPELFilename(0xAABBCCDD, date), 58 "2030112813060708_AABBCCDD"); 59 60 EXPECT_EQ(Repository::getPELFilename(0x3AFF1, date), 61 "2030112813060708_0003AFF1"); 62 63 EXPECT_EQ(Repository::getPELFilename(100, date), 64 "2030112813060708_00000064"); 65 66 EXPECT_EQ(Repository::getPELFilename(0, date), "2030112813060708_00000000"); 67 } 68 69 TEST_F(RepositoryTest, AddTest) 70 { 71 Repository repo{repoPath}; 72 auto data = pelDataFactory(TestPELType::pelSimple); 73 auto pel = std::make_unique<PEL>(data); 74 75 repo.add(pel); 76 77 // Check that the PEL was stored where it was supposed to be, 78 // and that it wrote the PEL data. 79 const auto ts = pel->privateHeader().commitTimestamp(); 80 auto name = Repository::getPELFilename(pel->id(), ts); 81 82 fs::path file = repoPath / "logs" / name; 83 EXPECT_TRUE(fs::exists(file)); 84 85 auto newData = readPELFile(file); 86 auto pelData = pel->data(); 87 EXPECT_EQ(*newData, pelData); 88 89 EXPECT_EQ(repo.lastPelID(), pel->id()); 90 } 91 92 TEST_F(RepositoryTest, RemoveTest) 93 { 94 using pelID = Repository::LogID::Pel; 95 using obmcID = Repository::LogID::Obmc; 96 97 // Add and remove a PEL from the repo 98 99 Repository repo{repoPath}; 100 101 auto data = pelDataFactory(TestPELType::pelSimple); 102 auto pel = std::make_unique<PEL>(data, 1); 103 104 pel->assignID(); 105 Repository::LogID id{pelID{pel->id()}, obmcID{pel->obmcLogID()}}; 106 107 repo.add(pel); 108 109 auto removedID = repo.remove(id); 110 ASSERT_TRUE(removedID); 111 EXPECT_EQ(*removedID, id); 112 113 EXPECT_FALSE(repo.hasPEL(id)); 114 115 // Try to remove it again, not there 116 EXPECT_FALSE(repo.remove(id)); 117 } 118 119 TEST_F(RepositoryTest, RestoreTest) 120 { 121 using pelID = Repository::LogID::Pel; 122 using obmcID = Repository::LogID::Obmc; 123 124 std::vector<Repository::LogID> ids; 125 126 { 127 Repository repo{repoPath}; 128 129 // Add some PELs to the repository 130 { 131 auto data = pelDataFactory(TestPELType::pelSimple); 132 auto pel = std::make_unique<PEL>(data, 1); 133 pel->assignID(); 134 repo.add(pel); 135 ids.emplace_back(pelID(pel->id()), obmcID(1)); 136 } 137 { 138 auto data = pelDataFactory(TestPELType::pelSimple); 139 auto pel = std::make_unique<PEL>(data, 2); 140 pel->assignID(); 141 repo.add(pel); 142 ids.emplace_back(pelID(pel->id()), obmcID(2)); 143 } 144 145 // Check they're there 146 EXPECT_TRUE(repo.hasPEL(ids[0])); 147 EXPECT_TRUE(repo.hasPEL(ids[1])); 148 149 // Do some other search tests while we're here. 150 151 // Search based on PEL ID 152 Repository::LogID id(pelID(ids[0].pelID)); 153 EXPECT_TRUE(repo.hasPEL(id)); 154 155 // Search based on OBMC log ID 156 id.pelID.id = 0; 157 id.obmcID = ids[0].obmcID; 158 EXPECT_TRUE(repo.hasPEL(id)); 159 160 // ... based on the other PEL ID 161 id.pelID = ids[1].pelID; 162 id.obmcID.id = 0; 163 EXPECT_TRUE(repo.hasPEL(id)); 164 165 // Not found 166 id.pelID.id = 99; 167 id.obmcID.id = 100; 168 EXPECT_FALSE(repo.hasPEL(id)); 169 170 // Try to remove it anyway 171 EXPECT_FALSE(repo.remove(id)); 172 } 173 174 { 175 // Restore and check they're still there, then 176 // remove them. 177 Repository repo{repoPath}; 178 EXPECT_TRUE(repo.hasPEL(ids[0])); 179 EXPECT_TRUE(repo.hasPEL(ids[1])); 180 181 repo.remove(ids[0]); 182 EXPECT_FALSE(repo.hasPEL(ids[0])); 183 184 repo.remove(ids[1]); 185 EXPECT_FALSE(repo.hasPEL(ids[1])); 186 } 187 } 188 189 TEST_F(RepositoryTest, TestGetPELData) 190 { 191 using ID = Repository::LogID; 192 Repository repo{repoPath}; 193 194 ID badID{ID::Pel(42)}; 195 auto noData = repo.getPELData(badID); 196 EXPECT_FALSE(noData); 197 198 // Add a PEL to the repo, and get the data back with getPELData. 199 auto data = pelDataFactory(TestPELType::pelSimple); 200 auto dataCopy = data; 201 auto pel = std::make_unique<PEL>(data); 202 auto pelID = pel->id(); 203 repo.add(pel); 204 205 ID id{ID::Pel(pelID)}; 206 auto pelData = repo.getPELData(id); 207 208 ASSERT_TRUE(pelData); 209 EXPECT_EQ(dataCopy, *pelData); 210 } 211 212 TEST_F(RepositoryTest, TestForEach) 213 { 214 Repository repo{repoPath}; 215 216 // Add 2 PELs 217 auto data = pelDataFactory(TestPELType::pelSimple); 218 auto pel = std::make_unique<PEL>(data); 219 repo.add(pel); 220 221 pel = std::make_unique<PEL>(data); 222 pel->assignID(); 223 pel->setCommitTime(); 224 repo.add(pel); 225 226 // Make a function that saves the IDs 227 std::vector<uint32_t> ids; 228 Repository::ForEachFunc f1 = [&ids](const PEL& pel) { 229 ids.push_back(pel.id()); 230 return false; 231 }; 232 233 repo.for_each(f1); 234 235 EXPECT_EQ(ids.size(), 2); 236 237 // Stop after the first time in. 238 Repository::ForEachFunc f2 = [&ids](const PEL& pel) { 239 ids.push_back(pel.id()); 240 return true; 241 }; 242 243 ids.clear(); 244 repo.for_each(f2); 245 EXPECT_EQ(ids.size(), 1); 246 } 247 248 TEST_F(RepositoryTest, TestSubscriptions) 249 { 250 std::vector<uint32_t> added; 251 std::vector<uint32_t> removed; 252 253 Repository::AddCallback ac = [&added](const PEL& pel) { 254 added.push_back(pel.id()); 255 }; 256 257 Repository::DeleteCallback dc = [&removed](uint32_t id) { 258 removed.push_back(id); 259 }; 260 261 Repository repo{repoPath}; 262 repo.subscribeToAdds("test", ac); 263 repo.subscribeToDeletes("test", dc); 264 265 auto data = pelDataFactory(TestPELType::pelSimple); 266 auto pel = std::make_unique<PEL>(data); 267 auto pelID = pel->id(); 268 repo.add(pel); 269 270 EXPECT_EQ(added.size(), 1); 271 272 using ID = Repository::LogID; 273 ID id{ID::Pel(pelID)}; 274 repo.remove(id); 275 276 EXPECT_EQ(removed.size(), 1); 277 278 repo.unsubscribeFromAdds("test"); 279 repo.unsubscribeFromDeletes("test"); 280 281 added.clear(); 282 removed.clear(); 283 284 repo.add(pel); 285 EXPECT_EQ(added.size(), 0); 286 287 repo.remove(id); 288 EXPECT_EQ(removed.size(), 0); 289 } 290 291 TEST_F(RepositoryTest, TestGetAttributes) 292 { 293 uint32_t pelID = 0; 294 std::bitset<16> actionFlags; 295 296 { 297 Repository repo{repoPath}; 298 299 // Add a PEL to the repo 300 auto data = pelDataFactory(TestPELType::pelSimple); 301 auto pel = std::make_unique<PEL>(data); 302 repo.add(pel); 303 304 pelID = pel->id(); 305 actionFlags = pel->userHeader().actionFlags(); 306 307 using ID = Repository::LogID; 308 ID id{ID::Pel(pelID)}; 309 310 auto a = repo.getPELAttributes(id); 311 EXPECT_TRUE(a); 312 EXPECT_EQ((*a).get().actionFlags, actionFlags); 313 314 id.pelID.id = 0; 315 a = repo.getPELAttributes(id); 316 EXPECT_FALSE(a); 317 } 318 319 { 320 // Restore the repository and check again 321 Repository repo{repoPath}; 322 323 using ID = Repository::LogID; 324 ID id{ID::Pel(pelID)}; 325 326 auto a = repo.getPELAttributes(id); 327 EXPECT_TRUE(a); 328 EXPECT_EQ((*a).get().actionFlags, actionFlags); 329 330 id.pelID.id = 0; 331 a = repo.getPELAttributes(id); 332 EXPECT_FALSE(a); 333 } 334 } 335 336 TEST_F(RepositoryTest, TestSetHostState) 337 { 338 // Add a PEL to the repo 339 auto data = pelDataFactory(TestPELType::pelSimple); 340 auto pel = std::make_unique<PEL>(data); 341 using ID = Repository::LogID; 342 ID id{ID::Pel(pel->id())}; 343 344 { 345 Repository repo{repoPath}; 346 347 repo.add(pel); 348 349 auto a = repo.getPELAttributes(id); 350 EXPECT_EQ((*a).get().hostState, TransmissionState::newPEL); 351 352 repo.setPELHostTransState(pel->id(), TransmissionState::acked); 353 354 // First, check the attributes 355 a = repo.getPELAttributes(id); 356 EXPECT_EQ((*a).get().hostState, TransmissionState::acked); 357 358 // Next, check the PEL data itself 359 auto pelData = repo.getPELData(id); 360 PEL newPEL{*pelData}; 361 EXPECT_EQ(newPEL.hostTransmissionState(), TransmissionState::acked); 362 } 363 364 { 365 // Now restore, and check again 366 Repository repo{repoPath}; 367 368 // First, check the attributes 369 auto a = repo.getPELAttributes(id); 370 EXPECT_EQ((*a).get().hostState, TransmissionState::acked); 371 372 // Next, check the PEL data itself 373 auto pelData = repo.getPELData(id); 374 PEL newPEL{*pelData}; 375 EXPECT_EQ(newPEL.hostTransmissionState(), TransmissionState::acked); 376 } 377 } 378 379 TEST_F(RepositoryTest, TestSetHMCState) 380 { 381 // Add a PEL to the repo 382 auto data = pelDataFactory(TestPELType::pelSimple); 383 auto pel = std::make_unique<PEL>(data); 384 using ID = Repository::LogID; 385 ID id{ID::Pel(pel->id())}; 386 387 { 388 Repository repo{repoPath}; 389 390 repo.add(pel); 391 392 auto a = repo.getPELAttributes(id); 393 EXPECT_EQ((*a).get().hmcState, TransmissionState::newPEL); 394 395 repo.setPELHMCTransState(pel->id(), TransmissionState::acked); 396 397 // First, check the attributes 398 a = repo.getPELAttributes(id); 399 EXPECT_EQ((*a).get().hmcState, TransmissionState::acked); 400 401 // Next, check the PEL data itself 402 auto pelData = repo.getPELData(id); 403 PEL newPEL{*pelData}; 404 EXPECT_EQ(newPEL.hmcTransmissionState(), TransmissionState::acked); 405 } 406 407 { 408 // Now restore, and check again 409 Repository repo{repoPath}; 410 411 // First, check the attributes 412 auto a = repo.getPELAttributes(id); 413 EXPECT_EQ((*a).get().hmcState, TransmissionState::acked); 414 415 // Next, check the PEL data itself 416 auto pelData = repo.getPELData(id); 417 PEL newPEL{*pelData}; 418 EXPECT_EQ(newPEL.hmcTransmissionState(), TransmissionState::acked); 419 } 420 } 421 422 TEST_F(RepositoryTest, TestGetPELFD) 423 { 424 Repository repo{repoPath}; 425 426 auto data = pelDataFactory(TestPELType::pelSimple); 427 auto pel = std::make_unique<PEL>(data); 428 pel->setCommitTime(); 429 pel->assignID(); 430 431 repo.add(pel); 432 433 using ID = Repository::LogID; 434 ID id{ID::Pel(pel->id())}; 435 436 auto fd = repo.getPELFD(id); 437 438 EXPECT_TRUE(fd); 439 440 // Get the size 441 struct stat s; 442 int r = fstat(*fd, &s); 443 ASSERT_EQ(r, 0); 444 445 auto size = s.st_size; 446 447 // Read the PEL data out of the FD 448 FILE* fp = fdopen(*fd, "r"); 449 ASSERT_NE(fp, nullptr); 450 451 std::vector<uint8_t> newData; 452 newData.resize(size); 453 r = fread(newData.data(), 1, size, fp); 454 EXPECT_EQ(r, size); 455 456 PEL newPEL{newData}; 457 458 EXPECT_TRUE(newPEL.valid()); 459 EXPECT_EQ(newPEL.id(), pel->id()); 460 461 fclose(fp); 462 463 // Call getPELFD again, this time with a bad ID 464 id.pelID.id = 42; 465 fd = repo.getPELFD(id); 466 467 EXPECT_FALSE(fd); 468 } 469 470 // Test the repo size statistics 471 TEST_F(RepositoryTest, TestRepoSizes) 472 { 473 uint32_t id = 1; 474 475 Repository repo{repoPath, 10000, 500}; 476 477 // All of the size stats are the sizes on disk a PEL takes up, 478 // which is different than the file size. Disk usage seems 479 // to have a granularity of 4096 bytes. This probably shouldn't 480 // be hardcoded, but I don't know how to look it up dynamically. 481 482 // All sizes are zero 483 { 484 const auto& stats = repo.getSizeStats(); 485 EXPECT_EQ(stats.total, 0); 486 EXPECT_EQ(stats.bmc, 0); 487 EXPECT_EQ(stats.nonBMC, 0); 488 EXPECT_EQ(stats.bmcServiceable, 0); 489 EXPECT_EQ(stats.bmcInfo, 0); 490 EXPECT_EQ(stats.nonBMCServiceable, 0); 491 EXPECT_EQ(stats.nonBMCInfo, 0); 492 } 493 494 // Add a 2000B BMC predictive error 495 auto data = pelFactory(id++, 'O', 0x20, 0x8800, 2000); 496 auto pel = std::make_unique<PEL>(data); 497 auto pelID1 = pel->id(); 498 repo.add(pel); 499 500 { 501 const auto& stats = repo.getSizeStats(); 502 EXPECT_EQ(stats.total, 4096); 503 EXPECT_EQ(stats.bmc, 4096); 504 EXPECT_EQ(stats.nonBMC, 0); 505 EXPECT_EQ(stats.bmcServiceable, 4096); 506 EXPECT_EQ(stats.bmcInfo, 0); 507 EXPECT_EQ(stats.nonBMCServiceable, 0); 508 EXPECT_EQ(stats.nonBMCInfo, 0); 509 } 510 511 // Add a 5000B BMC informational error 512 data = pelFactory(id++, 'O', 0x00, 0x8800, 5000); 513 pel = std::make_unique<PEL>(data); 514 auto pelID2 = pel->id(); 515 repo.add(pel); 516 517 { 518 const auto& stats = repo.getSizeStats(); 519 EXPECT_EQ(stats.total, 4096 + 8192); 520 EXPECT_EQ(stats.bmc, 4096 + 8192); 521 EXPECT_EQ(stats.nonBMC, 0); 522 EXPECT_EQ(stats.bmcServiceable, 4096); 523 EXPECT_EQ(stats.bmcInfo, 8192); 524 EXPECT_EQ(stats.nonBMCServiceable, 0); 525 EXPECT_EQ(stats.nonBMCInfo, 0); 526 } 527 528 // Add a 4000B Hostboot unrecoverable error 529 data = pelFactory(id++, 'B', 0x40, 0x8800, 4000); 530 pel = std::make_unique<PEL>(data); 531 auto pelID3 = pel->id(); 532 repo.add(pel); 533 534 { 535 const auto& stats = repo.getSizeStats(); 536 EXPECT_EQ(stats.total, 4096 + 8192 + 4096); 537 EXPECT_EQ(stats.bmc, 4096 + 8192); 538 EXPECT_EQ(stats.nonBMC, 4096); 539 EXPECT_EQ(stats.bmcServiceable, 4096); 540 EXPECT_EQ(stats.bmcInfo, 8192); 541 EXPECT_EQ(stats.nonBMCServiceable, 4096); 542 EXPECT_EQ(stats.nonBMCInfo, 0); 543 } 544 545 // Add a 5000B Hostboot informational error 546 data = pelFactory(id++, 'B', 0x00, 0x8800, 5000); 547 pel = std::make_unique<PEL>(data); 548 auto pelID4 = pel->id(); 549 repo.add(pel); 550 551 { 552 const auto& stats = repo.getSizeStats(); 553 EXPECT_EQ(stats.total, 4096 + 8192 + 4096 + 8192); 554 EXPECT_EQ(stats.bmc, 4096 + 8192); 555 EXPECT_EQ(stats.nonBMC, 4096 + 8192); 556 EXPECT_EQ(stats.bmcServiceable, 4096); 557 EXPECT_EQ(stats.bmcInfo, 8192); 558 EXPECT_EQ(stats.nonBMCServiceable, 4096); 559 EXPECT_EQ(stats.nonBMCInfo, 8192); 560 } 561 562 // Remove the BMC serviceable error 563 using ID = Repository::LogID; 564 ID id1{ID::Pel(pelID1)}; 565 566 repo.remove(id1); 567 { 568 const auto& stats = repo.getSizeStats(); 569 EXPECT_EQ(stats.total, 8192 + 4096 + 8192); 570 EXPECT_EQ(stats.bmc, 8192); 571 EXPECT_EQ(stats.nonBMC, 4096 + 8192); 572 EXPECT_EQ(stats.bmcServiceable, 0); 573 EXPECT_EQ(stats.bmcInfo, 8192); 574 EXPECT_EQ(stats.nonBMCServiceable, 4096); 575 EXPECT_EQ(stats.nonBMCInfo, 8192); 576 } 577 578 // Remove the Hostboot informational error 579 ID id4{ID::Pel(pelID4)}; 580 581 repo.remove(id4); 582 { 583 const auto& stats = repo.getSizeStats(); 584 EXPECT_EQ(stats.total, 8192 + 4096); 585 EXPECT_EQ(stats.bmc, 8192); 586 EXPECT_EQ(stats.nonBMC, 4096); 587 EXPECT_EQ(stats.bmcServiceable, 0); 588 EXPECT_EQ(stats.bmcInfo, 8192); 589 EXPECT_EQ(stats.nonBMCServiceable, 4096); 590 EXPECT_EQ(stats.nonBMCInfo, 0); 591 } 592 593 // Remove the BMC informational error 594 ID id2{ID::Pel(pelID2)}; 595 596 repo.remove(id2); 597 { 598 const auto& stats = repo.getSizeStats(); 599 EXPECT_EQ(stats.total, 4096); 600 EXPECT_EQ(stats.bmc, 0); 601 EXPECT_EQ(stats.nonBMC, 4096); 602 EXPECT_EQ(stats.bmcServiceable, 0); 603 EXPECT_EQ(stats.bmcInfo, 0); 604 EXPECT_EQ(stats.nonBMCServiceable, 4096); 605 EXPECT_EQ(stats.nonBMCInfo, 0); 606 } 607 608 // Remove the hostboot unrecoverable error 609 ID id3{ID::Pel(pelID3)}; 610 611 repo.remove(id3); 612 { 613 const auto& stats = repo.getSizeStats(); 614 EXPECT_EQ(stats.total, 0); 615 EXPECT_EQ(stats.bmc, 0); 616 EXPECT_EQ(stats.nonBMC, 0); 617 EXPECT_EQ(stats.bmcServiceable, 0); 618 EXPECT_EQ(stats.bmcInfo, 0); 619 EXPECT_EQ(stats.nonBMCServiceable, 0); 620 EXPECT_EQ(stats.nonBMCInfo, 0); 621 } 622 } 623 624 // Prune PELs, when no HMC/OS/PHYP acks 625 TEST_F(RepositoryTest, TestPruneNoAcks) 626 { 627 std::vector<uint32_t> id; 628 Repository repo{repoPath, 4096 * 20, 100}; 629 630 // Add 10 4096B (on disk) PELs of BMC nonInfo, Info and nonBMC info, 631 // nonInfo errors. None of them acked by PHYP, host, or HMC. 632 for (uint32_t i = 1; i <= 10; i++) 633 { 634 // BMC predictive 635 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 636 auto pel = std::make_unique<PEL>(data); 637 repo.add(pel); 638 639 // BMC info 640 data = pelFactory(i + 100, 'O', 0x0, 0x8800, 500); 641 pel = std::make_unique<PEL>(data); 642 repo.add(pel); 643 644 // Hostboot predictive 645 data = pelFactory(i + 200, 'B', 0x20, 0x8800, 500); 646 pel = std::make_unique<PEL>(data); 647 repo.add(pel); 648 649 // Hostboot info 650 data = pelFactory(i + 300, 'B', 0x0, 0x8800, 500); 651 pel = std::make_unique<PEL>(data); 652 repo.add(pel); 653 } 654 655 const auto& sizes = repo.getSizeStats(); 656 EXPECT_EQ(sizes.total, 4096 * 40); 657 658 // Sanity check the very first PELs with IDs 1 to 4 are 659 // there so we can check they are removed after the prune. 660 for (uint32_t i = 1; i < 5; i++) 661 { 662 Repository::LogID id{Repository::LogID::Pel{i}}; 663 EXPECT_TRUE(repo.getPELAttributes(id)); 664 } 665 666 // Prune down to 15%/30%/15%/30% = 90% total 667 auto IDs = repo.prune(id); 668 669 // Check the final sizes 670 EXPECT_EQ(sizes.total, 4096 * 18); // 90% of 20 PELs 671 EXPECT_EQ(sizes.bmcInfo, 4096 * 3); // 15% of 20 PELs 672 EXPECT_EQ(sizes.bmcServiceable, 4096 * 6); // 30% of 20 PELs 673 EXPECT_EQ(sizes.nonBMCInfo, 4096 * 3); // 15% of 20 PELs 674 EXPECT_EQ(sizes.nonBMCServiceable, 4096 * 6); // 30% of 20 PELs 675 676 // Check that at least the 4 oldest, which are the oldest of 677 // each type, were removed. 678 for (uint32_t i = 1; i < 5; i++) 679 { 680 Repository::LogID id{Repository::LogID::Pel{i}}; 681 EXPECT_FALSE(repo.getPELAttributes(id)); 682 683 // Make sure the corresponding OpenBMC event log ID which is 684 // 500 + the PEL ID is in the list. 685 EXPECT_TRUE(std::find(IDs.begin(), IDs.end(), 500 + i) != IDs.end()); 686 } 687 } 688 689 // Test that if filled completely with 1 type of PEL, that 690 // pruning still works properly 691 TEST_F(RepositoryTest, TestPruneInfoOnly) 692 { 693 std::vector<uint32_t> id; 694 Repository repo{repoPath, 4096 * 22, 100}; 695 696 // Fill 4096*23 bytes on disk of BMC info PELs 697 for (uint32_t i = 1; i <= 23; i++) 698 { 699 auto data = pelFactory(i, 'O', 0, 0x8800, 1000); 700 auto pel = std::make_unique<PEL>(data); 701 repo.add(pel); 702 } 703 704 const auto& sizes = repo.getSizeStats(); 705 EXPECT_EQ(sizes.total, 4096 * 23); 706 707 // Pruning to 15% of 4096 * 22 will leave 3 4096B PELs. 708 709 // Sanity check the oldest 20 are there so when they 710 // get pruned below we'll know they were removed. 711 for (uint32_t i = 1; i <= 20; i++) 712 { 713 Repository::LogID id{Repository::LogID::Pel{i}}; 714 EXPECT_TRUE(repo.getPELAttributes(id)); 715 } 716 717 auto IDs = repo.prune(id); 718 719 // Check the final sizes 720 EXPECT_EQ(sizes.total, 4096 * 3); 721 EXPECT_EQ(sizes.bmcInfo, 4096 * 3); 722 EXPECT_EQ(sizes.bmcServiceable, 0); 723 EXPECT_EQ(sizes.nonBMCInfo, 0); 724 EXPECT_EQ(sizes.nonBMCServiceable, 0); 725 726 EXPECT_EQ(IDs.size(), 20); 727 728 // Can no longer find the oldest 20 PELs. 729 for (uint32_t i = 1; i <= 20; i++) 730 { 731 Repository::LogID id{Repository::LogID::Pel{i}}; 732 EXPECT_FALSE(repo.getPELAttributes(id)); 733 EXPECT_TRUE(std::find(IDs.begin(), IDs.end(), 500 + i) != IDs.end()); 734 } 735 } 736 737 // Test that the HMC/OS/PHYP ack values affect the 738 // pruning order. 739 TEST_F(RepositoryTest, TestPruneWithAcks) 740 { 741 std::vector<uint32_t> id; 742 Repository repo{repoPath, 4096 * 20, 100}; 743 744 // Fill 30% worth of BMC non-info non-acked PELs 745 for (uint32_t i = 1; i <= 6; i++) 746 { 747 // BMC predictive 748 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 749 auto pel = std::make_unique<PEL>(data); 750 repo.add(pel); 751 } 752 753 // Add another PEL to push it over the 30%, each time adding 754 // a different type that should be pruned before the above ones 755 // even though those are older. 756 for (uint32_t i = 1; i <= 3; i++) 757 { 758 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 759 auto pel = std::make_unique<PEL>(data); 760 auto idToDelete = pel->obmcLogID(); 761 repo.add(pel); 762 763 if (0 == i) 764 { 765 repo.setPELHMCTransState(pel->id(), TransmissionState::acked); 766 } 767 else if (1 == i) 768 { 769 repo.setPELHostTransState(pel->id(), TransmissionState::acked); 770 } 771 else 772 { 773 repo.setPELHostTransState(pel->id(), TransmissionState::sent); 774 } 775 776 auto IDs = repo.prune(id); 777 EXPECT_EQ(repo.getSizeStats().total, 4096 * 6); 778 779 // The newest PEL should be the one deleted 780 ASSERT_EQ(IDs.size(), 1); 781 EXPECT_EQ(IDs[0], idToDelete); 782 } 783 } 784 785 // Test that the total number of PELs limit is enforced. 786 TEST_F(RepositoryTest, TestPruneTooManyPELs) 787 { 788 std::vector<uint32_t> id; 789 Repository repo{repoPath, 4096 * 100, 10}; 790 791 // Add 10, which is the limit and is still OK 792 for (uint32_t i = 1; i <= 10; i++) 793 { 794 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 795 auto pel = std::make_unique<PEL>(data); 796 repo.add(pel); 797 } 798 799 auto IDs = repo.prune(id); 800 801 // Nothing pruned yet 802 EXPECT_TRUE(IDs.empty()); 803 804 // Add 1 more PEL which will be too many. 805 { 806 auto data = pelFactory(11, 'O', 0x20, 0x8800, 500); 807 auto pel = std::make_unique<PEL>(data); 808 repo.add(pel); 809 } 810 811 // Now that's it's over the limit of 10, it will bring it down 812 // to 80%, which is 8 after it removes 3. 813 IDs = repo.prune(id); 814 EXPECT_EQ(repo.getSizeStats().total, 4096 * 8); 815 ASSERT_EQ(IDs.size(), 3); 816 817 // Check that it deleted the oldest ones. 818 // The OpenBMC log ID is the PEL ID + 500. 819 EXPECT_EQ(IDs[0], 500 + 1); 820 EXPECT_EQ(IDs[1], 500 + 2); 821 EXPECT_EQ(IDs[2], 500 + 3); 822 } 823 824 // Test the sizeWarning function 825 TEST_F(RepositoryTest, TestSizeWarning) 826 { 827 uint32_t id = 1; 828 Repository repo{repoPath, 100 * 4096, 500}; 829 830 EXPECT_FALSE(repo.sizeWarning()); 831 832 // 95% is still OK (disk size for these is 4096) 833 for (uint32_t i = 1; i <= 95; i++) 834 { 835 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 836 auto pel = std::make_unique<PEL>(data); 837 repo.add(pel); 838 } 839 840 EXPECT_FALSE(repo.sizeWarning()); 841 842 // Now at 96% 843 auto data = pelFactory(id++, 'B', 0x20, 0x8800, 500); 844 auto pel = std::make_unique<PEL>(data); 845 repo.add(pel); 846 847 EXPECT_TRUE(repo.sizeWarning()); 848 } 849 850 // Test sizeWarning when there are too many PEls 851 TEST_F(RepositoryTest, TestSizeWarningNumPELs) 852 { 853 Repository repo{repoPath, 4096 * 100, 5}; 854 855 EXPECT_FALSE(repo.sizeWarning()); 856 857 for (uint32_t i = 1; i <= 5; i++) 858 { 859 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 860 auto pel = std::make_unique<PEL>(data); 861 repo.add(pel); 862 } 863 864 EXPECT_FALSE(repo.sizeWarning()); 865 866 // Add 1 more for a total of 6, now over the limit 867 { 868 auto data = pelFactory(6, 'O', 0x20, 0x8800, 500); 869 auto pel = std::make_unique<PEL>(data); 870 repo.add(pel); 871 } 872 873 EXPECT_TRUE(repo.sizeWarning()); 874 } 875 876 // Test existense of archive file 877 TEST_F(RepositoryTest, TestArchiveFile) 878 { 879 using pelID = Repository::LogID::Pel; 880 using obmcID = Repository::LogID::Obmc; 881 882 // Add and remove a PEL from the repo 883 884 Repository repo{repoPath}; 885 886 fs::path archivePath = repoPath / "logs" / "archive"; 887 EXPECT_TRUE(fs::exists(archivePath)); 888 889 auto data = pelDataFactory(TestPELType::pelSimple); 890 auto pel = std::make_unique<PEL>(data, 1); 891 892 pel->assignID(); 893 Repository::LogID id{pelID{pel->id()}, obmcID{pel->obmcLogID()}}; 894 895 repo.add(pel); 896 897 auto path = repoPath / "logs" / 898 Repository::getPELFilename(pel->id(), pel->commitTime()); 899 EXPECT_TRUE(fs::exists(path)); 900 901 auto removedID = repo.remove(id); 902 ASSERT_TRUE(removedID); 903 EXPECT_EQ(*removedID, id); 904 905 archivePath /= Repository::getPELFilename(pel->id(), pel->commitTime()); 906 EXPECT_TRUE(fs::exists(archivePath)); 907 908 EXPECT_FALSE(repo.hasPEL(id)); 909 } 910 911 // Test archive folder size with sizeWarning function 912 TEST_F(RepositoryTest, TestArchiveSize) 913 { 914 using pelID = Repository::LogID::Pel; 915 using obmcID = Repository::LogID::Obmc; 916 917 // Create repo with max PEL=500 and space=4096*100 918 Repository repo{repoPath, 100 * 4096, 500}; 919 920 // Fill 94% (disk size for these is 4096) 921 for (uint32_t i = 1; i <= 94; i++) 922 { 923 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 924 auto pel = std::make_unique<PEL>(data); 925 repo.add(pel); 926 } 927 928 // Add another PEL which makes 95% still ok 929 auto data = pelDataFactory(TestPELType::pelSimple); 930 auto pel = std::make_unique<PEL>(data, 1); 931 pel->assignID(); 932 Repository::LogID id{pelID{pel->id()}, obmcID{pel->obmcLogID()}}; 933 repo.add(pel); 934 935 // With 95% full expect no size warning 936 EXPECT_FALSE(repo.sizeWarning()); 937 938 // Remove last created PEL 939 repo.remove(id); 940 941 // Repo is 94% full with one PEL in archive log 942 // Total repo size 95% full (including archive) still ok 943 EXPECT_FALSE(repo.sizeWarning()); 944 945 // Confirm the repo size 94% full 946 const auto& sizes = repo.getSizeStats(); 947 EXPECT_EQ(sizes.total, 4096 * 94); 948 949 // Make sure archive contain the one deleted file 950 fs::path archivePath = repoPath / "logs" / "archive"; 951 archivePath /= Repository::getPELFilename(pel->id(), pel->commitTime()); 952 EXPECT_TRUE(fs::exists(archivePath)); 953 954 // Add another PEL which makes repo 95% full 955 data = pelDataFactory(TestPELType::pelSimple); 956 pel = std::make_unique<PEL>(data, 1); 957 pel->assignID(); 958 Repository::LogID idx{pelID{pel->id()}, obmcID{pel->obmcLogID()}}; 959 repo.add(pel); 960 961 // Repo with 95% full + one archive file becomes 96% 962 // which is greater than the warning 963 // expect archive file to be deleted to get repo size back to 95% 964 EXPECT_FALSE(repo.sizeWarning()); 965 EXPECT_FALSE(fs::exists(archivePath)); 966 } 967 968 TEST_F(RepositoryTest, GetLogIDFoundTC) 969 { 970 // Add and Check the created LogId 971 972 Repository repo{repoPath}; 973 auto data = pelDataFactory(TestPELType::pelSimple); 974 auto pel = std::make_unique<PEL>(data, 1); 975 976 pel->assignID(); 977 978 repo.add(pel); 979 980 // Getting by PEL Id 981 Repository::LogID idWithPelId{Repository::LogID::Pel(pel->id())}; 982 auto logID = repo.getLogID(idWithPelId); 983 ASSERT_TRUE(logID.has_value()); 984 EXPECT_EQ(logID->obmcID.id, pel->obmcLogID()); 985 EXPECT_EQ(logID->pelID.id, pel->id()); 986 987 // Getting by OBMC Event Log Id 988 Repository::LogID idWithObmcLogId{ 989 Repository::LogID::Obmc(pel->obmcLogID())}; 990 logID = repo.getLogID(idWithObmcLogId); 991 ASSERT_TRUE(logID.has_value()); 992 EXPECT_EQ(logID->obmcID.id, pel->obmcLogID()); 993 EXPECT_EQ(logID->pelID.id, pel->id()); 994 } 995 996 TEST_F(RepositoryTest, GetLogIDNotFoundTC) 997 { 998 // Add and Check the created LogId 999 1000 Repository repo{repoPath}; 1001 auto data = pelDataFactory(TestPELType::pelSimple); 1002 auto pel = std::make_unique<PEL>(data, 1); 1003 1004 pel->assignID(); 1005 1006 repo.add(pel); 1007 1008 // Getting by invalid PEL Id 1009 Repository::LogID idWithPelId{Repository::LogID::Pel(0xFFFFFFFF)}; 1010 auto logID = repo.getLogID(idWithPelId); 1011 ASSERT_TRUE(!logID.has_value()); 1012 1013 // Getting by invalid OBMC Event Log ID 1014 Repository::LogID idWithObmcLogId{Repository::LogID::Obmc(0xFFFFFFFF)}; 1015 logID = repo.getLogID(idWithObmcLogId); 1016 ASSERT_TRUE(!logID.has_value()); 1017 } 1018 1019 // Test that OpenBMC log Id with hardware isolation entry is not removed. 1020 TEST_F(RepositoryTest, TestPruneWithIdHwIsoEntry) 1021 { 1022 std::vector<uint32_t> id{502}; 1023 Repository repo{repoPath, 4096 * 100, 10}; 1024 1025 // Add 10, which is the limit and is still OK 1026 for (uint32_t i = 1; i <= 10; i++) 1027 { 1028 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 1029 auto pel = std::make_unique<PEL>(data); 1030 repo.add(pel); 1031 } 1032 1033 auto IDs = repo.prune(id); 1034 1035 // Nothing pruned yet 1036 EXPECT_TRUE(IDs.empty()); 1037 1038 // Add 1 more PEL which will be too many. 1039 { 1040 auto data = pelFactory(11, 'O', 0x20, 0x8800, 500); 1041 auto pel = std::make_unique<PEL>(data); 1042 repo.add(pel); 1043 } 1044 1045 // Now that's it's over the limit of 10, it will bring it down 1046 // to 80%, which is 8 after it removes 3. 1047 IDs = repo.prune(id); 1048 EXPECT_EQ(repo.getSizeStats().total, 4096 * 8); 1049 ASSERT_EQ(IDs.size(), 3); 1050 1051 // Check that it deleted the oldest ones. 1052 // And the Id with hw isolation entry is NOT removed. 1053 // The OpenBMC log ID is the PEL ID + 500. 1054 EXPECT_EQ(IDs[0], 500 + 1); 1055 EXPECT_EQ(IDs[1], 500 + 3); 1056 EXPECT_EQ(IDs[2], 500 + 4); 1057 } 1058