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/fru_identity.hpp" 17 18 #include <gtest/gtest.h> 19 20 using namespace openpower::pels; 21 using namespace openpower::pels::src; 22 23 // Unflatten a FRUIdentity that is a HW FRU callout 24 TEST(FRUIdentityTest, TestHardwareFRU) 25 { 26 // Has PN, SN, CCIN 27 std::vector<uint8_t> data{'I', 'D', 0x1C, 0x1D, // type, size, flags 28 '1', '2', '3', '4', // PN 29 '5', '6', '7', 0x00, 'A', 'A', 'A', 'A', // CCIN 30 '1', '2', '3', '4', '5', '6', '7', '8', // SN 31 '9', 'A', 'B', 'C'}; 32 33 Stream stream{data}; 34 35 FRUIdentity fru{stream}; 36 37 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::hardwareFRU); 38 EXPECT_EQ(fru.flattenedSize(), data.size()); 39 EXPECT_EQ(fru.type(), 0x4944); 40 41 EXPECT_EQ(fru.getPN().value(), "1234567"); 42 EXPECT_EQ(fru.getCCIN().value(), "AAAA"); 43 EXPECT_EQ(fru.getSN().value(), "123456789ABC"); 44 EXPECT_FALSE(fru.getMaintProc()); 45 46 // Flatten 47 std::vector<uint8_t> newData; 48 Stream newStream{newData}; 49 fru.flatten(newStream); 50 EXPECT_EQ(data, newData); 51 } 52 53 // Unflatten a FRUIdentity that is a Maintenance Procedure callout 54 TEST(FRUIdentityTest, TestMaintProcedure) 55 { 56 // Only contains the maintenance procedure 57 std::vector<uint8_t> data{ 58 0x49, 0x44, 0x0C, 0x42, // type, size, flags 59 '1', '2', '3', '4', '5', '6', '7', 0x00 // Procedure 60 }; 61 62 Stream stream{data}; 63 64 FRUIdentity fru{stream}; 65 66 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::maintenanceProc); 67 EXPECT_EQ(fru.flattenedSize(), data.size()); 68 69 EXPECT_EQ(fru.getMaintProc().value(), "1234567"); 70 EXPECT_FALSE(fru.getPN()); 71 EXPECT_FALSE(fru.getCCIN()); 72 EXPECT_FALSE(fru.getSN()); 73 74 // Flatten 75 std::vector<uint8_t> newData; 76 Stream newStream{newData}; 77 fru.flatten(newStream); 78 EXPECT_EQ(data, newData); 79 } 80 81 // Try to unflatten garbage data 82 TEST(FRUIdentityTest, BadDataTest) 83 { 84 std::vector<uint8_t> data{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 85 0xFF, 0xFF, 0xFF, 0xFF}; 86 87 Stream stream{data}; 88 89 EXPECT_THROW(FRUIdentity fru{stream}, std::out_of_range); 90 } 91 92 void testHWCallout(const std::string& pn, const std::string ccin, 93 const std::string& sn, const std::string& expectedPN, 94 const std::string& expectedCCIN, 95 const std::string& expectedSN) 96 { 97 FRUIdentity fru{pn, ccin, sn}; 98 99 EXPECT_EQ(fru.flattenedSize(), 28); 100 EXPECT_EQ(fru.type(), 0x4944); 101 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::hardwareFRU); 102 EXPECT_EQ(fru.getPN().value(), expectedPN); 103 EXPECT_EQ(fru.getCCIN().value(), expectedCCIN); 104 EXPECT_EQ(fru.getSN().value(), expectedSN); 105 EXPECT_FALSE(fru.getMaintProc()); 106 107 // Flatten and unflatten, then compare again 108 std::vector<uint8_t> data; 109 Stream stream{data}; 110 fru.flatten(stream); 111 112 EXPECT_EQ(data.size(), fru.flattenedSize()); 113 114 stream.offset(0); 115 FRUIdentity newFRU{stream}; 116 117 EXPECT_EQ(newFRU.flattenedSize(), fru.flattenedSize()); 118 EXPECT_EQ(newFRU.type(), fru.type()); 119 EXPECT_EQ(newFRU.failingComponentType(), fru.failingComponentType()); 120 EXPECT_EQ(newFRU.getPN().value(), fru.getPN().value()); 121 EXPECT_EQ(newFRU.getCCIN().value(), fru.getCCIN().value()); 122 EXPECT_EQ(newFRU.getSN().value(), fru.getSN().value()); 123 EXPECT_FALSE(newFRU.getMaintProc()); 124 } 125 126 // Test the constructor that takes in a PN/SN/CCIN 127 TEST(FRUIdentityTest, CreateHardwareCalloutTest) 128 { 129 // The right sizes 130 testHWCallout("1234567", "1234", "123456789ABC", 131 // expected 132 "1234567", "1234", "123456789ABC"); 133 134 // Too long 135 testHWCallout("1234567long", "1234long", "123456789ABClong", 136 // expected 137 "1234567", "1234", "123456789ABC"); 138 // Too short 139 testHWCallout("11", "22", "333", 140 // expected 141 "11", "22", "333"); 142 143 // empty 144 testHWCallout("", "", "", 145 // expected 146 "", "", ""); 147 148 // Leading spaces in the part number will be stripped 149 testHWCallout(" 567", "1234", "123456789ABC", 150 // expected 151 "567", "1234", "123456789ABC"); 152 153 // All spaces in the part number 154 testHWCallout(" ", "1234", "123456789ABC", 155 // expected 156 "", "1234", "123456789ABC"); 157 } 158 159 // Test the constructor that takes in a maint procedure 160 TEST(FRUIdentityTest, CreateProcedureCalloutTest) 161 { 162 { 163 FRUIdentity fru{"no_vpd_for_fru"}; 164 165 EXPECT_EQ(fru.flattenedSize(), 12); 166 EXPECT_EQ(fru.type(), 0x4944); 167 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::maintenanceProc); 168 EXPECT_EQ(fru.getMaintProc().value(), "BMCSP01"); 169 EXPECT_FALSE(fru.getPN()); 170 EXPECT_FALSE(fru.getCCIN()); 171 EXPECT_FALSE(fru.getSN()); 172 173 // Flatten and unflatten, then compare again 174 std::vector<uint8_t> data; 175 Stream stream{data}; 176 fru.flatten(stream); 177 178 EXPECT_EQ(data.size(), fru.flattenedSize()); 179 180 stream.offset(0); 181 FRUIdentity newFRU{stream}; 182 183 EXPECT_EQ(newFRU.flattenedSize(), 12); 184 EXPECT_EQ(newFRU.type(), 0x4944); 185 EXPECT_EQ(newFRU.failingComponentType(), FRUIdentity::maintenanceProc); 186 EXPECT_EQ(newFRU.getMaintProc().value(), "BMCSP01"); 187 EXPECT_FALSE(newFRU.getPN()); 188 EXPECT_FALSE(newFRU.getCCIN()); 189 EXPECT_FALSE(newFRU.getSN()); 190 } 191 192 { 193 // Invalid maintenance procedure 194 FRUIdentity fru{"invalid"}; 195 196 EXPECT_EQ(fru.flattenedSize(), 12); 197 EXPECT_EQ(fru.type(), 0x4944); 198 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::maintenanceProc); 199 EXPECT_EQ(fru.getMaintProc().value(), "INVALID"); 200 EXPECT_FALSE(fru.getPN()); 201 EXPECT_FALSE(fru.getCCIN()); 202 EXPECT_FALSE(fru.getSN()); 203 } 204 205 { 206 // Raw maintenance procedure 207 FRUIdentity fru{"BMCSPXXLONG", CalloutValueType::raw}; 208 EXPECT_EQ(fru.getMaintProc().value(), "BMCSPXX"); 209 } 210 } 211 212 // Test the constructor that takes in a symbolic FRU. 213 TEST(FRUIdentityTest, CreateSymbolicFRUCalloutTest) 214 { 215 // Symbolic FRU (not trusted) 216 { 217 FRUIdentity fru{"service_docs", false}; 218 219 EXPECT_EQ(fru.flattenedSize(), 12); 220 EXPECT_EQ(fru.type(), 0x4944); 221 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::symbolicFRU); 222 EXPECT_EQ(fru.getPN().value(), "SVCDOCS"); 223 EXPECT_FALSE(fru.getMaintProc()); 224 EXPECT_FALSE(fru.getCCIN()); 225 EXPECT_FALSE(fru.getSN()); 226 227 // Flatten and unflatten, then compare again 228 std::vector<uint8_t> data; 229 Stream stream{data}; 230 fru.flatten(stream); 231 232 EXPECT_EQ(data.size(), fru.flattenedSize()); 233 234 stream.offset(0); 235 FRUIdentity newFRU{stream}; 236 237 EXPECT_EQ(newFRU.flattenedSize(), 12); 238 EXPECT_EQ(newFRU.type(), 0x4944); 239 EXPECT_EQ(newFRU.failingComponentType(), FRUIdentity::symbolicFRU); 240 EXPECT_EQ(newFRU.getPN().value(), "SVCDOCS"); 241 EXPECT_FALSE(newFRU.getMaintProc()); 242 EXPECT_FALSE(newFRU.getCCIN()); 243 EXPECT_FALSE(newFRU.getSN()); 244 } 245 246 // Trusted symbolic FRU 247 { 248 FRUIdentity fru{"service_docs", true}; 249 250 EXPECT_EQ(fru.flattenedSize(), 12); 251 EXPECT_EQ(fru.type(), 0x4944); 252 EXPECT_EQ(fru.failingComponentType(), 253 FRUIdentity::symbolicFRUTrustedLocCode); 254 EXPECT_EQ(fru.getPN().value(), "SVCDOCS"); 255 EXPECT_FALSE(fru.getMaintProc()); 256 EXPECT_FALSE(fru.getCCIN()); 257 EXPECT_FALSE(fru.getSN()); 258 } 259 260 // Invalid symbolic FRU 261 { 262 FRUIdentity fru{"garbage", false}; 263 264 EXPECT_EQ(fru.flattenedSize(), 12); 265 EXPECT_EQ(fru.type(), 0x4944); 266 EXPECT_EQ(fru.failingComponentType(), FRUIdentity::symbolicFRU); 267 EXPECT_EQ(fru.getPN().value(), "INVALID"); 268 EXPECT_FALSE(fru.getMaintProc()); 269 EXPECT_FALSE(fru.getCCIN()); 270 EXPECT_FALSE(fru.getSN()); 271 } 272 273 // Raw symbolic FRU 274 { 275 FRUIdentity fru{"SOMEFRULONG", CalloutValueType::raw, false}; 276 277 EXPECT_EQ(fru.getPN().value(), "SOMEFRU"); 278 } 279 } 280