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 Repository repo{repoPath, 4096 * 20, 100}; 628 629 // Add 10 4096B (on disk) PELs of BMC nonInfo, Info and nonBMC info, 630 // nonInfo errors. None of them acked by PHYP, host, or HMC. 631 for (uint32_t i = 1; i <= 10; i++) 632 { 633 // BMC predictive 634 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 635 auto pel = std::make_unique<PEL>(data); 636 repo.add(pel); 637 638 // BMC info 639 data = pelFactory(i + 100, 'O', 0x0, 0x8800, 500); 640 pel = std::make_unique<PEL>(data); 641 repo.add(pel); 642 643 // Hostboot predictive 644 data = pelFactory(i + 200, 'B', 0x20, 0x8800, 500); 645 pel = std::make_unique<PEL>(data); 646 repo.add(pel); 647 648 // Hostboot info 649 data = pelFactory(i + 300, 'B', 0x0, 0x8800, 500); 650 pel = std::make_unique<PEL>(data); 651 repo.add(pel); 652 } 653 654 const auto& sizes = repo.getSizeStats(); 655 EXPECT_EQ(sizes.total, 4096 * 40); 656 657 // Sanity check the very first PELs with IDs 1 to 4 are 658 // there so we can check they are removed after the prune. 659 for (uint32_t i = 1; i < 5; i++) 660 { 661 Repository::LogID id{Repository::LogID::Pel{i}}; 662 EXPECT_TRUE(repo.getPELAttributes(id)); 663 } 664 665 // Prune down to 15%/30%/15%/30% = 90% total 666 auto IDs = repo.prune(); 667 668 // Check the final sizes 669 EXPECT_EQ(sizes.total, 4096 * 18); // 90% of 20 PELs 670 EXPECT_EQ(sizes.bmcInfo, 4096 * 3); // 15% of 20 PELs 671 EXPECT_EQ(sizes.bmcServiceable, 4096 * 6); // 30% of 20 PELs 672 EXPECT_EQ(sizes.nonBMCInfo, 4096 * 3); // 15% of 20 PELs 673 EXPECT_EQ(sizes.nonBMCServiceable, 4096 * 6); // 30% of 20 PELs 674 675 // Check that at least the 4 oldest, which are the oldest of 676 // each type, were removed. 677 for (uint32_t i = 1; i < 5; i++) 678 { 679 Repository::LogID id{Repository::LogID::Pel{i}}; 680 EXPECT_FALSE(repo.getPELAttributes(id)); 681 682 // Make sure the corresponding OpenBMC event log ID which is 683 // 500 + the PEL ID is in the list. 684 EXPECT_TRUE(std::find(IDs.begin(), IDs.end(), 500 + i) != IDs.end()); 685 } 686 } 687 688 // Test that if filled completely with 1 type of PEL, that 689 // pruning still works properly 690 TEST_F(RepositoryTest, TestPruneInfoOnly) 691 { 692 Repository repo{repoPath, 4096 * 22, 100}; 693 694 // Fill 4096*23 bytes on disk of BMC info PELs 695 for (uint32_t i = 1; i <= 23; i++) 696 { 697 auto data = pelFactory(i, 'O', 0, 0x8800, 1000); 698 auto pel = std::make_unique<PEL>(data); 699 repo.add(pel); 700 } 701 702 const auto& sizes = repo.getSizeStats(); 703 EXPECT_EQ(sizes.total, 4096 * 23); 704 705 // Pruning to 15% of 4096 * 22 will leave 3 4096B PELs. 706 707 // Sanity check the oldest 20 are there so when they 708 // get pruned below we'll know they were removed. 709 for (uint32_t i = 1; i <= 20; i++) 710 { 711 Repository::LogID id{Repository::LogID::Pel{i}}; 712 EXPECT_TRUE(repo.getPELAttributes(id)); 713 } 714 715 auto IDs = repo.prune(); 716 717 // Check the final sizes 718 EXPECT_EQ(sizes.total, 4096 * 3); 719 EXPECT_EQ(sizes.bmcInfo, 4096 * 3); 720 EXPECT_EQ(sizes.bmcServiceable, 0); 721 EXPECT_EQ(sizes.nonBMCInfo, 0); 722 EXPECT_EQ(sizes.nonBMCServiceable, 0); 723 724 EXPECT_EQ(IDs.size(), 20); 725 726 // Can no longer find the oldest 20 PELs. 727 for (uint32_t i = 1; i <= 20; i++) 728 { 729 Repository::LogID id{Repository::LogID::Pel{i}}; 730 EXPECT_FALSE(repo.getPELAttributes(id)); 731 EXPECT_TRUE(std::find(IDs.begin(), IDs.end(), 500 + i) != IDs.end()); 732 } 733 } 734 735 // Test that the HMC/OS/PHYP ack values affect the 736 // pruning order. 737 TEST_F(RepositoryTest, TestPruneWithAcks) 738 { 739 Repository repo{repoPath, 4096 * 20, 100}; 740 741 // Fill 30% worth of BMC non-info non-acked PELs 742 for (uint32_t i = 1; i <= 6; i++) 743 { 744 // BMC predictive 745 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 746 auto pel = std::make_unique<PEL>(data); 747 repo.add(pel); 748 } 749 750 // Add another PEL to push it over the 30%, each time adding 751 // a different type that should be pruned before the above ones 752 // even though those are older. 753 for (uint32_t i = 1; i <= 3; i++) 754 { 755 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 756 auto pel = std::make_unique<PEL>(data); 757 auto idToDelete = pel->obmcLogID(); 758 repo.add(pel); 759 760 if (0 == i) 761 { 762 repo.setPELHMCTransState(pel->id(), TransmissionState::acked); 763 } 764 else if (1 == i) 765 { 766 repo.setPELHostTransState(pel->id(), TransmissionState::acked); 767 } 768 else 769 { 770 repo.setPELHostTransState(pel->id(), TransmissionState::sent); 771 } 772 773 auto IDs = repo.prune(); 774 EXPECT_EQ(repo.getSizeStats().total, 4096 * 6); 775 776 // The newest PEL should be the one deleted 777 ASSERT_EQ(IDs.size(), 1); 778 EXPECT_EQ(IDs[0], idToDelete); 779 } 780 } 781 782 // Test that the total number of PELs limit is enforced. 783 TEST_F(RepositoryTest, TestPruneTooManyPELs) 784 { 785 Repository repo{repoPath, 4096 * 100, 10}; 786 787 // Add 10, which is the limit and is still OK 788 for (uint32_t i = 1; i <= 10; i++) 789 { 790 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 791 auto pel = std::make_unique<PEL>(data); 792 repo.add(pel); 793 } 794 795 auto IDs = repo.prune(); 796 797 // Nothing pruned yet 798 EXPECT_TRUE(IDs.empty()); 799 800 // Add 1 more PEL which will be too many. 801 { 802 auto data = pelFactory(11, 'O', 0x20, 0x8800, 500); 803 auto pel = std::make_unique<PEL>(data); 804 repo.add(pel); 805 } 806 807 // Now that's it's over the limit of 10, it will bring it down 808 // to 80%, which is 8 after it removes 3. 809 IDs = repo.prune(); 810 EXPECT_EQ(repo.getSizeStats().total, 4096 * 8); 811 ASSERT_EQ(IDs.size(), 3); 812 813 // Check that it deleted the oldest ones. 814 // The OpenBMC log ID is the PEL ID + 500. 815 EXPECT_EQ(IDs[0], 500 + 1); 816 EXPECT_EQ(IDs[1], 500 + 2); 817 EXPECT_EQ(IDs[2], 500 + 3); 818 } 819 820 // Test the sizeWarning function 821 TEST_F(RepositoryTest, TestSizeWarning) 822 { 823 uint32_t id = 1; 824 Repository repo{repoPath, 100 * 4096, 500}; 825 826 EXPECT_FALSE(repo.sizeWarning()); 827 828 // 95% is still OK (disk size for these is 4096) 829 for (uint32_t i = 1; i <= 95; i++) 830 { 831 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 832 auto pel = std::make_unique<PEL>(data); 833 repo.add(pel); 834 } 835 836 EXPECT_FALSE(repo.sizeWarning()); 837 838 // Now at 96% 839 auto data = pelFactory(id++, 'B', 0x20, 0x8800, 500); 840 auto pel = std::make_unique<PEL>(data); 841 repo.add(pel); 842 843 EXPECT_TRUE(repo.sizeWarning()); 844 } 845 846 // Test sizeWarning when there are too many PEls 847 TEST_F(RepositoryTest, TestSizeWarningNumPELs) 848 { 849 Repository repo{repoPath, 4096 * 100, 5}; 850 851 EXPECT_FALSE(repo.sizeWarning()); 852 853 for (uint32_t i = 1; i <= 5; i++) 854 { 855 auto data = pelFactory(i, 'O', 0x20, 0x8800, 500); 856 auto pel = std::make_unique<PEL>(data); 857 repo.add(pel); 858 } 859 860 EXPECT_FALSE(repo.sizeWarning()); 861 862 // Add 1 more for a total of 6, now over the limit 863 { 864 auto data = pelFactory(6, 'O', 0x20, 0x8800, 500); 865 auto pel = std::make_unique<PEL>(data); 866 repo.add(pel); 867 } 868 869 EXPECT_TRUE(repo.sizeWarning()); 870 } 871