diff options
Diffstat (limited to 'test/openpower-pels/repository_test.cpp')
-rw-r--r-- | test/openpower-pels/repository_test.cpp | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/test/openpower-pels/repository_test.cpp b/test/openpower-pels/repository_test.cpp new file mode 100644 index 0000000..446e10e --- /dev/null +++ b/test/openpower-pels/repository_test.cpp @@ -0,0 +1,436 @@ +/** + * Copyright © 2019 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "extensions/openpower-pels/paths.hpp" +#include "extensions/openpower-pels/repository.hpp" +#include "pel_utils.hpp" + +#include <ext/stdio_filebuf.h> + +#include <filesystem> + +#include <gtest/gtest.h> + +using namespace openpower::pels; +namespace fs = std::filesystem; + +/** + * Clean the Repo after every testcase. + * And because we have PEL object, also clean up + * the log ID. + */ +class RepositoryTest : public CleanLogID +{ + protected: + void SetUp() override + { + repoPath = getPELRepoPath(); + } + + void TearDown() override + { + fs::remove_all(repoPath); + } + + fs::path repoPath; +}; + +TEST_F(RepositoryTest, FilenameTest) +{ + BCDTime date = {0x20, 0x30, 0x11, 0x28, 0x13, 0x6, 0x7, 0x8}; + + EXPECT_EQ(Repository::getPELFilename(0x12345678, date), + "2030112813060708_12345678"); + + EXPECT_EQ(Repository::getPELFilename(0xAABBCCDD, date), + "2030112813060708_AABBCCDD"); + + EXPECT_EQ(Repository::getPELFilename(0x3AFF1, date), + "2030112813060708_0003AFF1"); + + EXPECT_EQ(Repository::getPELFilename(100, date), + "2030112813060708_00000064"); + + EXPECT_EQ(Repository::getPELFilename(0, date), "2030112813060708_00000000"); +} + +TEST_F(RepositoryTest, AddTest) +{ + Repository repo{repoPath}; + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + + repo.add(pel); + + // Check that the PEL was stored where it was supposed to be, + // and that it wrote the PEL data. + const auto ts = pel->privateHeader().commitTimestamp(); + auto name = Repository::getPELFilename(pel->id(), ts); + + fs::path file = repoPath / "logs" / name; + EXPECT_TRUE(fs::exists(file)); + + auto newData = readPELFile(file); + auto pelData = pel->data(); + EXPECT_EQ(*newData, pelData); +} + +TEST_F(RepositoryTest, RestoreTest) +{ + using pelID = Repository::LogID::Pel; + using obmcID = Repository::LogID::Obmc; + + std::vector<Repository::LogID> ids; + + { + Repository repo{repoPath}; + + // Add some PELs to the repository + { + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data, 1); + pel->assignID(); + repo.add(pel); + ids.emplace_back(pelID(pel->id()), obmcID(1)); + } + { + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data, 2); + pel->assignID(); + repo.add(pel); + ids.emplace_back(pelID(pel->id()), obmcID(2)); + } + + // Check they're there + EXPECT_TRUE(repo.hasPEL(ids[0])); + EXPECT_TRUE(repo.hasPEL(ids[1])); + + // Do some other search tests while we're here. + + // Search based on PEL ID + Repository::LogID id(pelID(ids[0].pelID)); + EXPECT_TRUE(repo.hasPEL(id)); + + // Search based on OBMC log ID + id.pelID.id = 0; + id.obmcID = ids[0].obmcID; + EXPECT_TRUE(repo.hasPEL(id)); + + // ... based on the other PEL ID + id.pelID = ids[1].pelID; + id.obmcID.id = 0; + EXPECT_TRUE(repo.hasPEL(id)); + + // Not found + id.pelID.id = 99; + id.obmcID.id = 100; + EXPECT_FALSE(repo.hasPEL(id)); + } + + { + // Restore and check they're still there, then + // remove them. + Repository repo{repoPath}; + EXPECT_TRUE(repo.hasPEL(ids[0])); + EXPECT_TRUE(repo.hasPEL(ids[1])); + + repo.remove(ids[0]); + EXPECT_FALSE(repo.hasPEL(ids[0])); + + repo.remove(ids[1]); + EXPECT_FALSE(repo.hasPEL(ids[1])); + } +} + +TEST_F(RepositoryTest, TestGetPELData) +{ + using ID = Repository::LogID; + Repository repo{repoPath}; + + ID badID{ID::Pel(42)}; + auto noData = repo.getPELData(badID); + EXPECT_FALSE(noData); + + // Add a PEL to the repo, and get the data back with getPELData. + auto data = pelDataFactory(TestPELType::pelSimple); + auto dataCopy = data; + auto pel = std::make_unique<PEL>(data); + auto pelID = pel->id(); + repo.add(pel); + + ID id{ID::Pel(pelID)}; + auto pelData = repo.getPELData(id); + + ASSERT_TRUE(pelData); + EXPECT_EQ(dataCopy, *pelData); +} + +TEST_F(RepositoryTest, TestForEach) +{ + Repository repo{repoPath}; + + // Add 2 PELs + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + repo.add(pel); + + pel = std::make_unique<PEL>(data); + pel->assignID(); + pel->setCommitTime(); + repo.add(pel); + + // Make a function that saves the IDs + std::vector<uint32_t> ids; + Repository::ForEachFunc f1 = [&ids](const PEL& pel) { + ids.push_back(pel.id()); + return false; + }; + + repo.for_each(f1); + + EXPECT_EQ(ids.size(), 2); + + // Stop after the first time in. + Repository::ForEachFunc f2 = [&ids](const PEL& pel) { + ids.push_back(pel.id()); + return true; + }; + + ids.clear(); + repo.for_each(f2); + EXPECT_EQ(ids.size(), 1); +} + +TEST_F(RepositoryTest, TestSubscriptions) +{ + std::vector<uint32_t> added; + std::vector<uint32_t> removed; + + Repository::AddCallback ac = [&added](const PEL& pel) { + added.push_back(pel.id()); + }; + + Repository::DeleteCallback dc = [&removed](uint32_t id) { + removed.push_back(id); + }; + + Repository repo{repoPath}; + repo.subscribeToAdds("test", ac); + repo.subscribeToDeletes("test", dc); + + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + auto pelID = pel->id(); + repo.add(pel); + + EXPECT_EQ(added.size(), 1); + + using ID = Repository::LogID; + ID id{ID::Pel(pelID)}; + repo.remove(id); + + EXPECT_EQ(removed.size(), 1); + + repo.unsubscribeFromAdds("test"); + repo.unsubscribeFromDeletes("test"); + + added.clear(); + removed.clear(); + + repo.add(pel); + EXPECT_EQ(added.size(), 0); + + repo.remove(id); + EXPECT_EQ(removed.size(), 0); +} + +TEST_F(RepositoryTest, TestGetAttributes) +{ + uint32_t pelID = 0; + std::bitset<16> actionFlags; + + { + Repository repo{repoPath}; + + // Add a PEL to the repo + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + repo.add(pel); + + pelID = pel->id(); + actionFlags = pel->userHeader().actionFlags(); + + using ID = Repository::LogID; + ID id{ID::Pel(pelID)}; + + auto a = repo.getPELAttributes(id); + EXPECT_TRUE(a); + EXPECT_EQ((*a).get().actionFlags, actionFlags); + + id.pelID.id = 0; + a = repo.getPELAttributes(id); + EXPECT_FALSE(a); + } + + { + // Restore the repository and check again + Repository repo{repoPath}; + + using ID = Repository::LogID; + ID id{ID::Pel(pelID)}; + + auto a = repo.getPELAttributes(id); + EXPECT_TRUE(a); + EXPECT_EQ((*a).get().actionFlags, actionFlags); + + id.pelID.id = 0; + a = repo.getPELAttributes(id); + EXPECT_FALSE(a); + } +} + +TEST_F(RepositoryTest, TestSetHostState) +{ + // Add a PEL to the repo + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + using ID = Repository::LogID; + ID id{ID::Pel(pel->id())}; + + { + Repository repo{repoPath}; + + repo.add(pel); + + auto a = repo.getPELAttributes(id); + EXPECT_EQ((*a).get().hostState, TransmissionState::newPEL); + + repo.setPELHostTransState(pel->id(), TransmissionState::acked); + + // First, check the attributes + a = repo.getPELAttributes(id); + EXPECT_EQ((*a).get().hostState, TransmissionState::acked); + + // Next, check the PEL data itself + auto pelData = repo.getPELData(id); + PEL newPEL{*pelData}; + EXPECT_EQ(newPEL.hostTransmissionState(), TransmissionState::acked); + } + + { + // Now restore, and check again + Repository repo{repoPath}; + + // First, check the attributes + auto a = repo.getPELAttributes(id); + EXPECT_EQ((*a).get().hostState, TransmissionState::acked); + + // Next, check the PEL data itself + auto pelData = repo.getPELData(id); + PEL newPEL{*pelData}; + EXPECT_EQ(newPEL.hostTransmissionState(), TransmissionState::acked); + } +} + +TEST_F(RepositoryTest, TestSetHMCState) +{ + // Add a PEL to the repo + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + using ID = Repository::LogID; + ID id{ID::Pel(pel->id())}; + + { + Repository repo{repoPath}; + + repo.add(pel); + + auto a = repo.getPELAttributes(id); + EXPECT_EQ((*a).get().hmcState, TransmissionState::newPEL); + + repo.setPELHMCTransState(pel->id(), TransmissionState::acked); + + // First, check the attributes + a = repo.getPELAttributes(id); + EXPECT_EQ((*a).get().hmcState, TransmissionState::acked); + + // Next, check the PEL data itself + auto pelData = repo.getPELData(id); + PEL newPEL{*pelData}; + EXPECT_EQ(newPEL.hmcTransmissionState(), TransmissionState::acked); + } + + { + // Now restore, and check again + Repository repo{repoPath}; + + // First, check the attributes + auto a = repo.getPELAttributes(id); + EXPECT_EQ((*a).get().hmcState, TransmissionState::acked); + + // Next, check the PEL data itself + auto pelData = repo.getPELData(id); + PEL newPEL{*pelData}; + EXPECT_EQ(newPEL.hmcTransmissionState(), TransmissionState::acked); + } +} + +TEST_F(RepositoryTest, TestGetPELFD) +{ + Repository repo{repoPath}; + + auto data = pelDataFactory(TestPELType::pelSimple); + auto pel = std::make_unique<PEL>(data); + pel->setCommitTime(); + pel->assignID(); + + repo.add(pel); + + using ID = Repository::LogID; + ID id{ID::Pel(pel->id())}; + + auto fd = repo.getPELFD(id); + + EXPECT_TRUE(fd); + + // Get the size + struct stat s; + int r = fstat(*fd, &s); + ASSERT_EQ(r, 0); + + auto size = s.st_size; + + // Read the PEL data out of the FD + FILE* fp = fdopen(*fd, "r"); + ASSERT_NE(fp, nullptr); + + std::vector<uint8_t> newData; + newData.resize(size); + r = fread(newData.data(), 1, size, fp); + EXPECT_EQ(r, size); + + PEL newPEL{newData}; + + EXPECT_TRUE(newPEL.valid()); + EXPECT_EQ(newPEL.id(), pel->id()); + + fclose(fp); + + // Call getPELFD again, this time with a bad ID + id.pelID.id = 42; + fd = repo.getPELFD(id); + + EXPECT_FALSE(fd); +} |