blob: 74c396c7955ca2b42d0976e263b6198cb9ec291b [file] [log] [blame]
Matt Spinler97f7abc2019-11-06 09:40:23 -06001/**
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 */
Matt Spinler6c9662c2019-10-09 11:27:20 -050016#include "extensions/openpower-pels/callout.hpp"
17#include "pel_utils.hpp"
18
19#include <gtest/gtest.h>
20
21using namespace openpower::pels;
22using namespace openpower::pels::src;
23
24// Unflatten the callout section with all three substructures
25TEST(CalloutTest, TestUnflattenAllSubstructures)
26{
27 // The base data.
28 std::vector<uint8_t> data{
29 0xFF, 0x2F, 'H', 8, // size, flags, priority, LC length
30 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
31 };
32
33 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
34 auto pceIdentity = srcDataFactory(TestSRCType::pceIdentityStructure);
35 auto mrus = srcDataFactory(TestSRCType::mruStructure);
36
37 // Add all 3 substructures
38 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
39 data.insert(data.end(), pceIdentity.begin(), pceIdentity.end());
40 data.insert(data.end(), mrus.begin(), mrus.end());
41
42 // The final size
43 data[0] = data.size();
44
45 Stream stream{data};
46 Callout callout{stream};
47
48 EXPECT_EQ(callout.flattenedSize(), data.size());
49 EXPECT_EQ(callout.priority(), 'H');
50 EXPECT_EQ(callout.locationCode(), "U12-P1");
51
52 // Spot check the 3 substructures
53 EXPECT_TRUE(callout.fruIdentity());
54 EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
55
56 EXPECT_TRUE(callout.pceIdentity());
57 EXPECT_EQ(callout.pceIdentity()->enclosureName(), "PCENAME12");
58
59 EXPECT_TRUE(callout.mru());
60 EXPECT_EQ(callout.mru()->mrus().size(), 4);
61 EXPECT_EQ(callout.mru()->mrus().at(3).id, 0x04040404);
62
63 // Now flatten
64 std::vector<uint8_t> newData;
65 Stream newStream{newData};
66
67 callout.flatten(newStream);
68 EXPECT_EQ(data, newData);
69}
70
71TEST(CalloutTest, TestUnflattenOneSubstructure)
72{
73 std::vector<uint8_t> data{
74 0xFF, 0x28, 'H', 0x08, // size, flags, priority, LC length
75 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
76 };
77
78 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
79
80 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
81
82 // The final size
83 data[0] = data.size();
84
85 Stream stream{data};
86 Callout callout{stream};
87
88 EXPECT_EQ(callout.flattenedSize(), data.size());
89
90 // Spot check the substructure
91 EXPECT_TRUE(callout.fruIdentity());
92 EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
93
94 // Not present
95 EXPECT_FALSE(callout.pceIdentity());
96 EXPECT_FALSE(callout.mru());
97
98 // Now flatten
99 std::vector<uint8_t> newData;
100 Stream newStream{newData};
101
102 callout.flatten(newStream);
103 EXPECT_EQ(data, newData);
104}
105
106TEST(CalloutTest, TestUnflattenTwoSubstructures)
107{
108 std::vector<uint8_t> data{
109 0xFF, 0x2B, 'H', 0x08, // size, flags, priority, LC length
110 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
111 };
112
113 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
114 auto pceIdentity = srcDataFactory(TestSRCType::pceIdentityStructure);
115
116 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
117 data.insert(data.end(), pceIdentity.begin(), pceIdentity.end());
118
119 // The final size
120 data[0] = data.size();
121
122 Stream stream{data};
123 Callout callout{stream};
124
125 EXPECT_EQ(callout.flattenedSize(), data.size());
126
127 // Spot check the 2 substructures
128 EXPECT_TRUE(callout.fruIdentity());
129 EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
130
131 EXPECT_TRUE(callout.pceIdentity());
132 EXPECT_EQ(callout.pceIdentity()->enclosureName(), "PCENAME12");
133
134 // Not present
135 EXPECT_FALSE(callout.mru());
136
137 // Now flatten
138 std::vector<uint8_t> newData;
139 Stream newStream{newData};
140
141 callout.flatten(newStream);
142 EXPECT_EQ(data, newData);
143}
144
145TEST(CalloutTest, TestNoLocationCode)
146{
147 std::vector<uint8_t> data{
148 0xFF, 0x2B, 'H', 0x00 // size, flags, priority, LC length
149 };
150
151 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
152 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
153
154 // The final size
155 data[0] = data.size();
156
157 Stream stream{data};
158 Callout callout{stream};
159
160 EXPECT_TRUE(callout.locationCode().empty());
161}
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500162
163// Create a callout object by passing in the hardware fields to add
164TEST(CalloutTest, TestHardwareCallout)
165{
166 constexpr size_t fruIdentitySize = 28;
167
168 {
169 Callout callout{CalloutPriority::high, "U99-42.5-P1-C2-E1", "1234567",
170 "ABCD", "123456789ABC"};
171
172 // size/flags/pri/locsize fields +
173 // rounded up location code length +
174 // FRUIdentity size
175 size_t size = 4 + 20 + fruIdentitySize;
176
177 EXPECT_EQ(callout.flags(),
178 Callout::calloutType | Callout::fruIdentIncluded);
179
180 EXPECT_EQ(callout.flattenedSize(), size);
181 EXPECT_EQ(callout.priority(), 'H');
182 EXPECT_EQ(callout.locationCode(), "U99-42.5-P1-C2-E1");
183 EXPECT_EQ(callout.locationCodeSize(), 20);
184
185 auto& fru = callout.fruIdentity();
186 EXPECT_EQ(fru->getPN().value(), "1234567");
187 EXPECT_EQ(fru->getCCIN().value(), "ABCD");
188 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
189 }
190
191 {
192 // A 3B location code, plus null = 4
193 Callout callout{CalloutPriority::high, "123", "1234567", "ABCD",
194 "123456789ABC"};
195
196 size_t size = 4 + 4 + fruIdentitySize;
197 EXPECT_EQ(callout.locationCodeSize(), 4);
198 EXPECT_EQ(callout.flattenedSize(), size);
199 EXPECT_EQ(callout.locationCode(), "123");
200 }
201
202 {
203 // A 4B location code, plus null = 5, then pad to 8
204 Callout callout{CalloutPriority::high, "1234", "1234567", "ABCD",
205 "123456789ABC"};
206
207 size_t size = 4 + 8 + fruIdentitySize;
208 EXPECT_EQ(callout.locationCodeSize(), 8);
209 EXPECT_EQ(callout.flattenedSize(), size);
210 EXPECT_EQ(callout.locationCode(), "1234");
211 }
212
213 {
214 // A truncated location code (80 is max size, including null)
215 std::string locCode(81, 'L');
216 Callout callout{CalloutPriority::high, locCode, "1234567", "ABCD",
217 "123456789ABC"};
218
219 size_t size = 4 + 80 + fruIdentitySize;
220 EXPECT_EQ(callout.locationCodeSize(), 80);
221 EXPECT_EQ(callout.flattenedSize(), size);
222
223 // take off 1 to get to 80, and another for the null
224 locCode = locCode.substr(0, locCode.size() - 2);
225 EXPECT_EQ(callout.locationCode(), locCode);
226 }
227
228 {
229 // A truncated location code by 1 because of the null
230 std::string locCode(80, 'L');
231 Callout callout{CalloutPriority::high, locCode, "1234567", "ABCD",
232 "123456789ABC"};
233
234 size_t size = 4 + 80 + fruIdentitySize;
235 EXPECT_EQ(callout.locationCodeSize(), 80);
236 EXPECT_EQ(callout.flattenedSize(), size);
237
238 locCode.pop_back();
239 EXPECT_EQ(callout.locationCode(), locCode);
240 }
241
242 {
243 // Max size location code
244 std::string locCode(79, 'L');
245 Callout callout{CalloutPriority::low, locCode, "1234567", "ABCD",
246 "123456789ABC"};
247
248 size_t size = 4 + 80 + fruIdentitySize;
249 EXPECT_EQ(callout.locationCodeSize(), 80);
250 EXPECT_EQ(callout.flattenedSize(), size);
251
252 EXPECT_EQ(callout.locationCode(), locCode);
253
254 // How about we flatten/unflatten this last one
255 std::vector<uint8_t> data;
256 Stream stream{data};
257
258 callout.flatten(stream);
259
260 {
261 Stream newStream{data};
262 Callout newCallout{newStream};
263
264 EXPECT_EQ(newCallout.flags(),
265 Callout::calloutType | Callout::fruIdentIncluded);
266
267 EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
268 EXPECT_EQ(newCallout.priority(), callout.priority());
269 EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
270 EXPECT_EQ(newCallout.locationCodeSize(),
271 callout.locationCodeSize());
272
273 auto& fru = newCallout.fruIdentity();
274 EXPECT_EQ(fru->getPN().value(), "1234567");
275 EXPECT_EQ(fru->getCCIN().value(), "ABCD");
276 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
277 }
278 }
279}
280
281// Create a callout object by passing in the maintenance procedure to add.
282TEST(CalloutTest, TestProcedureCallout)
283{
Matt Spinlera27e2e52020-04-09 11:06:11 -0500284 Callout callout{CalloutPriority::medium, "no_vpd_for_fru"};
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500285
286 // size/flags/pri/locsize fields + FRUIdentity size
287 // No location code.
288 size_t size = 4 + 12;
289
290 EXPECT_EQ(callout.flags(),
291 Callout::calloutType | Callout::fruIdentIncluded);
292
293 EXPECT_EQ(callout.flattenedSize(), size);
294 EXPECT_EQ(callout.priority(), 'M');
295 EXPECT_EQ(callout.locationCode(), "");
296 EXPECT_EQ(callout.locationCodeSize(), 0);
297
298 auto& fru = callout.fruIdentity();
299 EXPECT_EQ(fru->getMaintProc().value(), "BMCSP01");
300
301 // flatten/unflatten
302 std::vector<uint8_t> data;
303 Stream stream{data};
304
305 callout.flatten(stream);
306
307 Stream newStream{data};
308 Callout newCallout{newStream};
309
310 EXPECT_EQ(newCallout.flags(),
311 Callout::calloutType | Callout::fruIdentIncluded);
312
313 EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
314 EXPECT_EQ(newCallout.priority(), callout.priority());
315 EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
316 EXPECT_EQ(newCallout.locationCodeSize(), callout.locationCodeSize());
317
318 auto& newFRU = newCallout.fruIdentity();
319 EXPECT_EQ(newFRU->getMaintProc().value(), fru->getMaintProc().value());
320}
Matt Spinlera86ec992020-04-09 12:42:07 -0500321
322// Create a callout object by passing in the symbolic FRU to add.
323TEST(CalloutTest, TestSymbolicFRUCallout)
324{
325 // symbolic FRU with a location code
326 {
327 Callout callout{CalloutPriority::high, "service_docs", "P1-C3", false};
328
329 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
330 size_t size = 4 + 8 + 12;
331
332 EXPECT_EQ(callout.flags(),
333 Callout::calloutType | Callout::fruIdentIncluded);
334
335 EXPECT_EQ(callout.flattenedSize(), size);
336 EXPECT_EQ(callout.priority(), 'H');
337 EXPECT_EQ(callout.locationCode(), "P1-C3");
338 EXPECT_EQ(callout.locationCodeSize(), 8);
339
340 auto& fru = callout.fruIdentity();
341
342 EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
343 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
344 }
345
346 // symbolic FRU without a location code
347 {
348 Callout callout{CalloutPriority::high, "service_docs", "", false};
349
350 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
351 size_t size = 4 + 0 + 12;
352
353 EXPECT_EQ(callout.flags(),
354 Callout::calloutType | Callout::fruIdentIncluded);
355
356 EXPECT_EQ(callout.flattenedSize(), size);
357 EXPECT_EQ(callout.priority(), 'H');
358 EXPECT_EQ(callout.locationCode(), "");
359 EXPECT_EQ(callout.locationCodeSize(), 0);
360
361 auto& fru = callout.fruIdentity();
362
363 EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
364 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
365 }
366
367 // symbolic FRU with a trusted location code
368 {
369 Callout callout{CalloutPriority::high, "service_docs", "P1-C3", true};
370
371 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
372 size_t size = 4 + 8 + 12;
373
374 EXPECT_EQ(callout.flags(),
375 Callout::calloutType | Callout::fruIdentIncluded);
376
377 EXPECT_EQ(callout.flattenedSize(), size);
378 EXPECT_EQ(callout.priority(), 'H');
379 EXPECT_EQ(callout.locationCode(), "P1-C3");
380 EXPECT_EQ(callout.locationCodeSize(), 8);
381
382 auto& fru = callout.fruIdentity();
383 EXPECT_EQ(fru->failingComponentType(),
384 FRUIdentity::symbolicFRUTrustedLocCode);
385 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
386 }
387}