blob: daa2ab6c82131299571932758197718e017b944d [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 }
Matt Spinler5ab39972020-08-13 13:02:28 -0500279
280 {
281 // With MRUs
282 std::vector<MRU::MRUCallout> mruList{{'H', 1}, {'H', 2}};
283
284 Callout callout{CalloutPriority::high, "U99-P5", "1234567", "ABCD",
285 "123456789ABC", mruList};
286
287 EXPECT_EQ(callout.flags(), Callout::calloutType |
288 Callout::fruIdentIncluded |
289 Callout::mruIncluded);
290
291 EXPECT_EQ(callout.priority(), 'H');
292 EXPECT_EQ(callout.locationCode(), "U99-P5");
293 EXPECT_EQ(callout.locationCodeSize(), 8);
294
295 auto& fru = callout.fruIdentity();
296 EXPECT_EQ(fru->getPN().value(), "1234567");
297 EXPECT_EQ(fru->getCCIN().value(), "ABCD");
298 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
299
300 auto& mruSection = callout.mru();
301 EXPECT_EQ(mruSection->mrus().size(), 2);
302 EXPECT_EQ(mruSection->mrus().at(0).priority, 'H');
303 EXPECT_EQ(mruSection->mrus().at(0).id, 1);
304 EXPECT_EQ(mruSection->mrus().at(1).priority, 'H');
305 EXPECT_EQ(mruSection->mrus().at(1).id, 2);
306 }
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500307}
308
309// Create a callout object by passing in the maintenance procedure to add.
310TEST(CalloutTest, TestProcedureCallout)
311{
Matt Spinler479b6922021-08-17 16:34:59 -0500312 Callout callout{CalloutPriority::medium, "bmc_code"};
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500313
314 // size/flags/pri/locsize fields + FRUIdentity size
315 // No location code.
316 size_t size = 4 + 12;
317
318 EXPECT_EQ(callout.flags(),
319 Callout::calloutType | Callout::fruIdentIncluded);
320
321 EXPECT_EQ(callout.flattenedSize(), size);
322 EXPECT_EQ(callout.priority(), 'M');
323 EXPECT_EQ(callout.locationCode(), "");
324 EXPECT_EQ(callout.locationCodeSize(), 0);
325
326 auto& fru = callout.fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500327 EXPECT_EQ(fru->getMaintProc().value(), "BMC0001");
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500328
329 // flatten/unflatten
330 std::vector<uint8_t> data;
331 Stream stream{data};
332
333 callout.flatten(stream);
334
335 Stream newStream{data};
336 Callout newCallout{newStream};
337
338 EXPECT_EQ(newCallout.flags(),
339 Callout::calloutType | Callout::fruIdentIncluded);
340
341 EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
342 EXPECT_EQ(newCallout.priority(), callout.priority());
343 EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
344 EXPECT_EQ(newCallout.locationCodeSize(), callout.locationCodeSize());
345
346 auto& newFRU = newCallout.fruIdentity();
347 EXPECT_EQ(newFRU->getMaintProc().value(), fru->getMaintProc().value());
Matt Spinler468aab52020-08-13 11:04:31 -0500348
349 // Use raw procedure value
350
Matt Spinlerea2873d2021-08-18 10:35:40 -0500351 Callout rawCallout{CalloutPriority::medium, "BMCXXXX",
Matt Spinler468aab52020-08-13 11:04:31 -0500352 CalloutValueType::raw};
353 auto& rawFRU = rawCallout.fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500354 EXPECT_EQ(rawFRU->getMaintProc().value(), "BMCXXXX");
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500355}
Matt Spinlera86ec992020-04-09 12:42:07 -0500356
357// Create a callout object by passing in the symbolic FRU to add.
358TEST(CalloutTest, TestSymbolicFRUCallout)
359{
360 // symbolic FRU with a location code
361 {
362 Callout callout{CalloutPriority::high, "service_docs", "P1-C3", false};
363
364 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
365 size_t size = 4 + 8 + 12;
366
367 EXPECT_EQ(callout.flags(),
368 Callout::calloutType | Callout::fruIdentIncluded);
369
370 EXPECT_EQ(callout.flattenedSize(), size);
371 EXPECT_EQ(callout.priority(), 'H');
372 EXPECT_EQ(callout.locationCode(), "P1-C3");
373 EXPECT_EQ(callout.locationCodeSize(), 8);
374
375 auto& fru = callout.fruIdentity();
376
377 EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
378 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
379 }
380
381 // symbolic FRU without a location code
382 {
383 Callout callout{CalloutPriority::high, "service_docs", "", false};
384
385 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
386 size_t size = 4 + 0 + 12;
387
388 EXPECT_EQ(callout.flags(),
389 Callout::calloutType | Callout::fruIdentIncluded);
390
391 EXPECT_EQ(callout.flattenedSize(), size);
392 EXPECT_EQ(callout.priority(), 'H');
393 EXPECT_EQ(callout.locationCode(), "");
394 EXPECT_EQ(callout.locationCodeSize(), 0);
395
396 auto& fru = callout.fruIdentity();
397
398 EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
399 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
400 }
401
402 // symbolic FRU with a trusted location code
403 {
404 Callout callout{CalloutPriority::high, "service_docs", "P1-C3", true};
405
406 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
407 size_t size = 4 + 8 + 12;
408
409 EXPECT_EQ(callout.flags(),
410 Callout::calloutType | Callout::fruIdentIncluded);
411
412 EXPECT_EQ(callout.flattenedSize(), size);
413 EXPECT_EQ(callout.priority(), 'H');
414 EXPECT_EQ(callout.locationCode(), "P1-C3");
415 EXPECT_EQ(callout.locationCodeSize(), 8);
416
417 auto& fru = callout.fruIdentity();
418 EXPECT_EQ(fru->failingComponentType(),
419 FRUIdentity::symbolicFRUTrustedLocCode);
420 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
421 }
Matt Spinler468aab52020-08-13 11:04:31 -0500422
423 // symbolic FRU with raw FRU value
424 {
425 {
426 Callout callout{CalloutPriority::high, "SYMBFRU",
427 CalloutValueType::raw, "", false};
428
429 auto& fru = callout.fruIdentity();
430
431 EXPECT_EQ(fru->getPN().value(), "SYMBFRU");
432 }
433 }
Matt Spinlera86ec992020-04-09 12:42:07 -0500434}