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