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