blob: 12f8c2b688f79fe2cb8a1cd89ca447f50a404460 [file] [log] [blame]
/**
* 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/callout.hpp"
#include "pel_utils.hpp"
#include <gtest/gtest.h>
using namespace openpower::pels;
using namespace openpower::pels::src;
// Unflatten the callout section with all three substructures
TEST(CalloutTest, TestUnflattenAllSubstructures)
{
// The base data.
std::vector<uint8_t> data{
0xFF, 0x2F, 'H', 8, // size, flags, priority, LC length
'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
};
auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
auto pceIdentity = srcDataFactory(TestSRCType::pceIdentityStructure);
auto mrus = srcDataFactory(TestSRCType::mruStructure);
// Add all 3 substructures
data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
data.insert(data.end(), pceIdentity.begin(), pceIdentity.end());
data.insert(data.end(), mrus.begin(), mrus.end());
// The final size
data[0] = data.size();
Stream stream{data};
Callout callout{stream};
EXPECT_EQ(callout.flattenedSize(), data.size());
EXPECT_EQ(callout.priority(), 'H');
EXPECT_EQ(callout.locationCode(), "U12-P1");
// Spot check the 3 substructures
EXPECT_TRUE(callout.fruIdentity());
EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
EXPECT_TRUE(callout.pceIdentity());
EXPECT_EQ(callout.pceIdentity()->enclosureName(), "PCENAME12");
EXPECT_TRUE(callout.mru());
EXPECT_EQ(callout.mru()->mrus().size(), 4);
EXPECT_EQ(callout.mru()->mrus().at(3).id, 0x04040404);
// Now flatten
std::vector<uint8_t> newData;
Stream newStream{newData};
callout.flatten(newStream);
EXPECT_EQ(data, newData);
}
TEST(CalloutTest, TestUnflattenOneSubstructure)
{
std::vector<uint8_t> data{
0xFF, 0x28, 'H', 0x08, // size, flags, priority, LC length
'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
};
auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
// The final size
data[0] = data.size();
Stream stream{data};
Callout callout{stream};
EXPECT_EQ(callout.flattenedSize(), data.size());
// Spot check the substructure
EXPECT_TRUE(callout.fruIdentity());
EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
// Not present
EXPECT_FALSE(callout.pceIdentity());
EXPECT_FALSE(callout.mru());
// Now flatten
std::vector<uint8_t> newData;
Stream newStream{newData};
callout.flatten(newStream);
EXPECT_EQ(data, newData);
}
TEST(CalloutTest, TestUnflattenTwoSubstructures)
{
std::vector<uint8_t> data{
0xFF, 0x2B, 'H', 0x08, // size, flags, priority, LC length
'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
};
auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
auto pceIdentity = srcDataFactory(TestSRCType::pceIdentityStructure);
data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
data.insert(data.end(), pceIdentity.begin(), pceIdentity.end());
// The final size
data[0] = data.size();
Stream stream{data};
Callout callout{stream};
EXPECT_EQ(callout.flattenedSize(), data.size());
// Spot check the 2 substructures
EXPECT_TRUE(callout.fruIdentity());
EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
EXPECT_TRUE(callout.pceIdentity());
EXPECT_EQ(callout.pceIdentity()->enclosureName(), "PCENAME12");
// Not present
EXPECT_FALSE(callout.mru());
// Now flatten
std::vector<uint8_t> newData;
Stream newStream{newData};
callout.flatten(newStream);
EXPECT_EQ(data, newData);
}
TEST(CalloutTest, TestNoLocationCode)
{
std::vector<uint8_t> data{
0xFF, 0x2B, 'H', 0x00 // size, flags, priority, LC length
};
auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
// The final size
data[0] = data.size();
Stream stream{data};
Callout callout{stream};
EXPECT_TRUE(callout.locationCode().empty());
}
// Create a callout object by passing in the hardware fields to add
TEST(CalloutTest, TestHardwareCallout)
{
constexpr size_t fruIdentitySize = 28;
{
Callout callout{CalloutPriority::high, "U99-42.5-P1-C2-E1", "1234567",
"ABCD", "123456789ABC"};
// size/flags/pri/locsize fields +
// rounded up location code length +
// FRUIdentity size
size_t size = 4 + 20 + fruIdentitySize;
EXPECT_EQ(callout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.priority(), 'H');
EXPECT_EQ(callout.locationCode(), "U99-42.5-P1-C2-E1");
EXPECT_EQ(callout.locationCodeSize(), 20);
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->getPN().value(), "1234567");
EXPECT_EQ(fru->getCCIN().value(), "ABCD");
EXPECT_EQ(fru->getSN().value(), "123456789ABC");
}
{
// A 3B location code, plus null = 4
Callout callout{CalloutPriority::high, "123", "1234567", "ABCD",
"123456789ABC"};
size_t size = 4 + 4 + fruIdentitySize;
EXPECT_EQ(callout.locationCodeSize(), 4);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.locationCode(), "123");
}
{
// A 4B location code, plus null = 5, then pad to 8
Callout callout{CalloutPriority::high, "1234", "1234567", "ABCD",
"123456789ABC"};
size_t size = 4 + 8 + fruIdentitySize;
EXPECT_EQ(callout.locationCodeSize(), 8);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.locationCode(), "1234");
}
{
// A truncated location code (80 is max size, including null)
std::string locCode(81, 'L');
Callout callout{CalloutPriority::high, locCode, "1234567", "ABCD",
"123456789ABC"};
size_t size = 4 + 80 + fruIdentitySize;
EXPECT_EQ(callout.locationCodeSize(), 80);
EXPECT_EQ(callout.flattenedSize(), size);
// take off 1 to get to 80, and another for the null
locCode = locCode.substr(0, locCode.size() - 2);
EXPECT_EQ(callout.locationCode(), locCode);
}
{
// A truncated location code by 1 because of the null
std::string locCode(80, 'L');
Callout callout{CalloutPriority::high, locCode, "1234567", "ABCD",
"123456789ABC"};
size_t size = 4 + 80 + fruIdentitySize;
EXPECT_EQ(callout.locationCodeSize(), 80);
EXPECT_EQ(callout.flattenedSize(), size);
locCode.pop_back();
EXPECT_EQ(callout.locationCode(), locCode);
}
{
// Max size location code
std::string locCode(79, 'L');
Callout callout{CalloutPriority::low, locCode, "1234567", "ABCD",
"123456789ABC"};
size_t size = 4 + 80 + fruIdentitySize;
EXPECT_EQ(callout.locationCodeSize(), 80);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.locationCode(), locCode);
// How about we flatten/unflatten this last one
std::vector<uint8_t> data;
Stream stream{data};
callout.flatten(stream);
{
Stream newStream{data};
Callout newCallout{newStream};
EXPECT_EQ(newCallout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
EXPECT_EQ(newCallout.priority(), callout.priority());
EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
EXPECT_EQ(newCallout.locationCodeSize(),
callout.locationCodeSize());
auto& fru = newCallout.fruIdentity();
EXPECT_EQ(fru->getPN().value(), "1234567");
EXPECT_EQ(fru->getCCIN().value(), "ABCD");
EXPECT_EQ(fru->getSN().value(), "123456789ABC");
}
}
{
// With MRUs
std::vector<MRU::MRUCallout> mruList{{'H', 1}, {'H', 2}};
Callout callout{CalloutPriority::high, "U99-P5", "1234567", "ABCD",
"123456789ABC", mruList};
EXPECT_EQ(callout.flags(), Callout::calloutType |
Callout::fruIdentIncluded |
Callout::mruIncluded);
EXPECT_EQ(callout.priority(), 'H');
EXPECT_EQ(callout.locationCode(), "U99-P5");
EXPECT_EQ(callout.locationCodeSize(), 8);
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->getPN().value(), "1234567");
EXPECT_EQ(fru->getCCIN().value(), "ABCD");
EXPECT_EQ(fru->getSN().value(), "123456789ABC");
auto& mruSection = callout.mru();
EXPECT_EQ(mruSection->mrus().size(), 2);
EXPECT_EQ(mruSection->mrus().at(0).priority, 'H');
EXPECT_EQ(mruSection->mrus().at(0).id, 1);
EXPECT_EQ(mruSection->mrus().at(1).priority, 'H');
EXPECT_EQ(mruSection->mrus().at(1).id, 2);
}
}
// Create a callout object by passing in the maintenance procedure to add.
TEST(CalloutTest, TestProcedureCallout)
{
Callout callout{CalloutPriority::medium, "no_vpd_for_fru"};
// size/flags/pri/locsize fields + FRUIdentity size
// No location code.
size_t size = 4 + 12;
EXPECT_EQ(callout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.priority(), 'M');
EXPECT_EQ(callout.locationCode(), "");
EXPECT_EQ(callout.locationCodeSize(), 0);
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->getMaintProc().value(), "BMCSP01");
// flatten/unflatten
std::vector<uint8_t> data;
Stream stream{data};
callout.flatten(stream);
Stream newStream{data};
Callout newCallout{newStream};
EXPECT_EQ(newCallout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
EXPECT_EQ(newCallout.priority(), callout.priority());
EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
EXPECT_EQ(newCallout.locationCodeSize(), callout.locationCodeSize());
auto& newFRU = newCallout.fruIdentity();
EXPECT_EQ(newFRU->getMaintProc().value(), fru->getMaintProc().value());
// Use raw procedure value
Callout rawCallout{CalloutPriority::medium, "BMCSPXX",
CalloutValueType::raw};
auto& rawFRU = rawCallout.fruIdentity();
EXPECT_EQ(rawFRU->getMaintProc().value(), "BMCSPXX");
}
// Create a callout object by passing in the symbolic FRU to add.
TEST(CalloutTest, TestSymbolicFRUCallout)
{
// symbolic FRU with a location code
{
Callout callout{CalloutPriority::high, "service_docs", "P1-C3", false};
// size/flags/pri/locsize fields + plus loc + FRUIdentity size
size_t size = 4 + 8 + 12;
EXPECT_EQ(callout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.priority(), 'H');
EXPECT_EQ(callout.locationCode(), "P1-C3");
EXPECT_EQ(callout.locationCodeSize(), 8);
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
}
// symbolic FRU without a location code
{
Callout callout{CalloutPriority::high, "service_docs", "", false};
// size/flags/pri/locsize fields + plus loc + FRUIdentity size
size_t size = 4 + 0 + 12;
EXPECT_EQ(callout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.priority(), 'H');
EXPECT_EQ(callout.locationCode(), "");
EXPECT_EQ(callout.locationCodeSize(), 0);
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
}
// symbolic FRU with a trusted location code
{
Callout callout{CalloutPriority::high, "service_docs", "P1-C3", true};
// size/flags/pri/locsize fields + plus loc + FRUIdentity size
size_t size = 4 + 8 + 12;
EXPECT_EQ(callout.flags(),
Callout::calloutType | Callout::fruIdentIncluded);
EXPECT_EQ(callout.flattenedSize(), size);
EXPECT_EQ(callout.priority(), 'H');
EXPECT_EQ(callout.locationCode(), "P1-C3");
EXPECT_EQ(callout.locationCodeSize(), 8);
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->failingComponentType(),
FRUIdentity::symbolicFRUTrustedLocCode);
EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
}
// symbolic FRU with raw FRU value
{
{
Callout callout{CalloutPriority::high, "SYMBFRU",
CalloutValueType::raw, "", false};
auto& fru = callout.fruIdentity();
EXPECT_EQ(fru->getPN().value(), "SYMBFRU");
}
}
}