xref: /openbmc/phosphor-logging/test/openpower-pels/src_callout_test.cpp (revision 81a91e3ee4bf962111cf555ab9d3c3c51000fa3b)
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/callout.hpp"
17 #include "pel_utils.hpp"
18 
19 #include <gtest/gtest.h>
20 
21 using namespace openpower::pels;
22 using namespace openpower::pels::src;
23 
24 // Unflatten the callout section with all three substructures
25 TEST(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 
71 TEST(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 
106 TEST(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 
145 TEST(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 }
162 
163 // Create a callout object by passing in the hardware fields to add
164 TEST(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.
282 TEST(CalloutTest, TestProcedureCallout)
283 {
284     Callout callout{CalloutPriority::medium, "no_vpd_for_fru"};
285 
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 }
321 
322 // Create a callout object by passing in the symbolic FRU to add.
323 TEST(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 }
388