blob: dbb831fe06093543143c5930c6f95d67a27a1f85 [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 Spinlerf9bae182019-10-09 13:37:38 -050016#include "extensions/openpower-pels/src.hpp"
Matt Spinler075e5ba2020-02-21 15:46:00 -060017#include "mocks.hpp"
Matt Spinlerf9bae182019-10-09 13:37:38 -050018#include "pel_utils.hpp"
19
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080020#include <fstream>
21
Matt Spinlerf9bae182019-10-09 13:37:38 -050022#include <gtest/gtest.h>
23
24using namespace openpower::pels;
Matt Spinlered046852020-03-13 13:58:15 -050025using ::testing::_;
William A. Kennington IIIb41fa542021-05-29 14:45:16 -070026using ::testing::DoAll;
Matt Spinlered046852020-03-13 13:58:15 -050027using ::testing::InvokeWithoutArgs;
Matt Spinler075e5ba2020-02-21 15:46:00 -060028using ::testing::NiceMock;
29using ::testing::Return;
Matt Spinlered046852020-03-13 13:58:15 -050030using ::testing::SetArgReferee;
Matt Spinler3bdd0112020-08-27 10:24:34 -050031using ::testing::Throw;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080032namespace fs = std::filesystem;
Matt Spinlerf9bae182019-10-09 13:37:38 -050033
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080034const auto testRegistry = R"(
35{
36"PELs":
37[
38 {
39 "Name": "xyz.openbmc_project.Error.Test",
40 "Subsystem": "bmc_firmware",
41 "SRC":
42 {
43 "ReasonCode": "0xABCD",
44 "Words6To9":
45 {
46 "6":
47 {
48 "Description": "Component ID",
49 "AdditionalDataPropSource": "COMPID"
50 },
51 "7":
52 {
53 "Description": "Failure count",
54 "AdditionalDataPropSource": "FREQUENCY"
55 },
56 "8":
57 {
58 "Description": "Time period",
59 "AdditionalDataPropSource": "DURATION"
60 },
61 "9":
62 {
63 "Description": "Error code",
64 "AdditionalDataPropSource": "ERRORCODE"
65 }
66 }
67 },
68 "Documentation":
69 {
70 "Description": "A Component Fault",
71 "Message": "Comp %1 failed %2 times over %3 secs with ErrorCode %4",
72 "MessageArgSources":
73 [
74 "SRCWord6", "SRCWord7", "SRCWord8", "SRCWord9"
75 ]
76 }
77 }
78]
79}
80)";
81
82class SRCTest : public ::testing::Test
83{
84 protected:
85 static void SetUpTestCase()
86 {
87 char path[] = "/tmp/srctestXXXXXX";
88 regDir = mkdtemp(path);
89 }
90
91 static void TearDownTestCase()
92 {
93 fs::remove_all(regDir);
94 }
95
96 static std::string writeData(const char* data)
97 {
98 fs::path path = regDir / "registry.json";
99 std::ofstream stream{path};
100 stream << data;
101 return path;
102 }
103
104 static fs::path regDir;
105};
106
107fs::path SRCTest::regDir{};
108
109TEST_F(SRCTest, UnflattenFlattenTestNoCallouts)
Matt Spinlerf9bae182019-10-09 13:37:38 -0500110{
Matt Spinler42828bd2019-10-11 10:39:30 -0500111 auto data = pelDataFactory(TestPELType::primarySRCSection);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500112
113 Stream stream{data};
114 SRC src{stream};
115
116 EXPECT_TRUE(src.valid());
117
118 EXPECT_EQ(src.header().id, 0x5053);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600119 EXPECT_EQ(src.header().size, 0x50);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500120 EXPECT_EQ(src.header().version, 0x01);
121 EXPECT_EQ(src.header().subType, 0x01);
122 EXPECT_EQ(src.header().componentID, 0x0202);
123
124 EXPECT_EQ(src.version(), 0x02);
125 EXPECT_EQ(src.flags(), 0x00);
126 EXPECT_EQ(src.hexWordCount(), 9);
127 EXPECT_EQ(src.size(), 0x48);
128
129 const auto& hexwords = src.hexwordData();
Matt Spinlerbd716f02019-10-15 10:54:11 -0500130 EXPECT_EQ(0x02020255, hexwords[0]);
131 EXPECT_EQ(0x03030310, hexwords[1]);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500132 EXPECT_EQ(0x04040404, hexwords[2]);
133 EXPECT_EQ(0x05050505, hexwords[3]);
134 EXPECT_EQ(0x06060606, hexwords[4]);
135 EXPECT_EQ(0x07070707, hexwords[5]);
136 EXPECT_EQ(0x08080808, hexwords[6]);
137 EXPECT_EQ(0x09090909, hexwords[7]);
138
139 EXPECT_EQ(src.asciiString(), "BD8D5678 ");
140 EXPECT_FALSE(src.callouts());
141
142 // Flatten
143 std::vector<uint8_t> newData;
144 Stream newStream{newData};
145
146 src.flatten(newStream);
147 EXPECT_EQ(data, newData);
148}
149
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800150TEST_F(SRCTest, UnflattenFlattenTest2Callouts)
Matt Spinlerf9bae182019-10-09 13:37:38 -0500151{
Matt Spinler42828bd2019-10-11 10:39:30 -0500152 auto data = pelDataFactory(TestPELType::primarySRCSection2Callouts);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500153
154 Stream stream{data};
155 SRC src{stream};
156
157 EXPECT_TRUE(src.valid());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500158 EXPECT_EQ(src.flags(), 0x01); // Additional sections within the SRC.
Matt Spinlerf9bae182019-10-09 13:37:38 -0500159
160 // Spot check the SRC fields, but they're the same as above
161 EXPECT_EQ(src.asciiString(), "BD8D5678 ");
162
163 // There should be 2 callouts
164 const auto& calloutsSection = src.callouts();
165 ASSERT_TRUE(calloutsSection);
166 const auto& callouts = calloutsSection->callouts();
167 EXPECT_EQ(callouts.size(), 2);
168
169 // spot check that each callout has the right substructures
170 EXPECT_TRUE(callouts.front()->fruIdentity());
171 EXPECT_FALSE(callouts.front()->pceIdentity());
172 EXPECT_FALSE(callouts.front()->mru());
173
174 EXPECT_TRUE(callouts.back()->fruIdentity());
175 EXPECT_TRUE(callouts.back()->pceIdentity());
176 EXPECT_TRUE(callouts.back()->mru());
177
178 // Flatten
179 std::vector<uint8_t> newData;
180 Stream newStream{newData};
181
182 src.flatten(newStream);
183 EXPECT_EQ(data, newData);
184}
Matt Spinlerbd716f02019-10-15 10:54:11 -0500185
186// Create an SRC from the message registry
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800187TEST_F(SRCTest, CreateTestNoCallouts)
Matt Spinlerbd716f02019-10-15 10:54:11 -0500188{
189 message::Entry entry;
190 entry.src.type = 0xBD;
191 entry.src.reasonCode = 0xABCD;
192 entry.subsystem = 0x42;
193 entry.src.powerFault = true;
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800194 entry.src.hexwordADFields = {
195 {5, {"TEST1", "DESCR1"}}, // Not a user defined word
196 {6, {"TEST1", "DESCR1"}},
197 {7, {"TEST2", "DESCR2"}},
198 {8, {"TEST3", "DESCR3"}},
199 {9, {"TEST4", "DESCR4"}}};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500200
201 // Values for the SRC words pointed to above
202 std::vector<std::string> adData{"TEST1=0x12345678", "TEST2=12345678",
203 "TEST3=0XDEF", "TEST4=Z"};
204 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600205 NiceMock<MockDataInterface> dataIface;
206
207 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
208
209 SRC src{entry, ad, dataIface};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500210
211 EXPECT_TRUE(src.valid());
212 EXPECT_TRUE(src.isPowerFaultEvent());
213 EXPECT_EQ(src.size(), baseSRCSize);
214
215 const auto& hexwords = src.hexwordData();
216
217 // The spec always refers to SRC words 2 - 9, and as the hexwordData()
218 // array index starts at 0 use the math in the [] below to make it easier
219 // to tell what is being accessed.
220 EXPECT_EQ(hexwords[2 - 2] & 0xF0000000, 0); // Partition dump status
221 EXPECT_EQ(hexwords[2 - 2] & 0x00F00000, 0); // Partition boot type
222 EXPECT_EQ(hexwords[2 - 2] & 0x000000FF, 0x55); // SRC format
223 EXPECT_EQ(hexwords[3 - 2] & 0x000000FF, 0x10); // BMC position
Matt Spinler075e5ba2020-02-21 15:46:00 -0600224 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0xABCD0000); // Motherboard CCIN
Matt Spinlerbd716f02019-10-15 10:54:11 -0500225
226 // Validate more fields here as the code starts filling them in.
227
228 // Ensure hex word 5 wasn't allowed to be set to TEST1's contents
229 EXPECT_EQ(hexwords[5 - 2], 0);
230
231 // The user defined hex word fields specifed in the additional data.
232 EXPECT_EQ(hexwords[6 - 2], 0x12345678); // TEST1
233 EXPECT_EQ(hexwords[7 - 2], 12345678); // TEST2
234 EXPECT_EQ(hexwords[8 - 2], 0xdef); // TEST3
235 EXPECT_EQ(hexwords[9 - 2], 0); // TEST4, but can't convert a 'Z'
236
237 EXPECT_EQ(src.asciiString(), "BD42ABCD ");
238
239 // No callouts
240 EXPECT_FALSE(src.callouts());
241
242 // May as well spot check the flatten/unflatten
243 std::vector<uint8_t> data;
244 Stream stream{data};
245 src.flatten(stream);
246
247 stream.offset(0);
248 SRC newSRC{stream};
249
250 EXPECT_TRUE(newSRC.valid());
251 EXPECT_EQ(newSRC.isPowerFaultEvent(), src.isPowerFaultEvent());
252 EXPECT_EQ(newSRC.asciiString(), src.asciiString());
253 EXPECT_FALSE(newSRC.callouts());
254}
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800255
Vijay Lobof3702bb2021-04-09 15:10:19 -0500256// Create an SRC to test POWER_THERMAL_CRITICAL_FAULT set to TRUE
257// sets the power fault bit in SRC
258TEST_F(SRCTest, PowerFaultTest)
259{
260 message::Entry entry;
261 entry.src.type = 0xBD;
262 entry.src.reasonCode = 0xABCD;
263 entry.subsystem = 0x42;
264 entry.src.powerFault = false;
265
266 // Values for the SRC words pointed to above
267 std::vector<std::string> adData{"POWER_THERMAL_CRITICAL_FAULT=TRUE",
268 "TEST2=12345678", "TEST3=0XDEF", "TEST4=Z"};
269 AdditionalData ad{adData};
270 NiceMock<MockDataInterface> dataIface;
271
272 SRC src{entry, ad, dataIface};
273
274 EXPECT_TRUE(src.valid());
275 EXPECT_TRUE(src.isPowerFaultEvent());
276 EXPECT_EQ(src.size(), baseSRCSize);
277}
278
Matt Spinler075e5ba2020-02-21 15:46:00 -0600279// Test when the CCIN string isn't a 4 character number
280TEST_F(SRCTest, BadCCINTest)
281{
282 message::Entry entry;
283 entry.src.type = 0xBD;
284 entry.src.reasonCode = 0xABCD;
285 entry.subsystem = 0x42;
286 entry.src.powerFault = false;
287
288 std::vector<std::string> adData{};
289 AdditionalData ad{adData};
290 NiceMock<MockDataInterface> dataIface;
291
292 // First it isn't a number, then it is too long,
293 // then it is empty.
294 EXPECT_CALL(dataIface, getMotherboardCCIN)
295 .WillOnce(Return("X"))
296 .WillOnce(Return("12345"))
297 .WillOnce(Return(""));
298
299 // The CCIN in the first half should still be 0 each time.
300 {
301 SRC src{entry, ad, dataIface};
302 EXPECT_TRUE(src.valid());
303 const auto& hexwords = src.hexwordData();
304 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
305 }
306
307 {
308 SRC src{entry, ad, dataIface};
309 EXPECT_TRUE(src.valid());
310 const auto& hexwords = src.hexwordData();
311 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
312 }
313
314 {
315 SRC src{entry, ad, dataIface};
316 EXPECT_TRUE(src.valid());
317 const auto& hexwords = src.hexwordData();
318 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
319 }
320}
321
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800322// Test the getErrorDetails function
323TEST_F(SRCTest, MessageSubstitutionTest)
324{
325 auto path = SRCTest::writeData(testRegistry);
326 message::Registry registry{path};
327 auto entry = registry.lookup("0xABCD", message::LookupType::reasonCode);
328
329 std::vector<std::string> adData{"COMPID=0x1", "FREQUENCY=0x4",
330 "DURATION=30", "ERRORCODE=0x01ABCDEF"};
331 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600332 NiceMock<MockDataInterface> dataIface;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800333
Matt Spinler075e5ba2020-02-21 15:46:00 -0600334 SRC src{*entry, ad, dataIface};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800335 EXPECT_TRUE(src.valid());
336
337 auto errorDetails = src.getErrorDetails(registry, DetailLevel::message);
338 ASSERT_TRUE(errorDetails);
339 EXPECT_EQ(
340 errorDetails.value(),
341 "Comp 0x1 failed 0x4 times over 0x1E secs with ErrorCode 0x1ABCDEF");
342}
Matt Spinlered046852020-03-13 13:58:15 -0500343// Test that an inventory path callout string is
344// converted into the appropriate FRU callout.
345TEST_F(SRCTest, InventoryCalloutTest)
346{
347 message::Entry entry;
348 entry.src.type = 0xBD;
349 entry.src.reasonCode = 0xABCD;
350 entry.subsystem = 0x42;
351 entry.src.powerFault = false;
352
353 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
354 AdditionalData ad{adData};
355 NiceMock<MockDataInterface> dataIface;
356
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500357 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
358 .WillOnce(Return("UTMS-P1"));
359
360 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500361 .Times(1)
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500362 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
363 SetArgReferee<3>("123456789ABC")));
Matt Spinlered046852020-03-13 13:58:15 -0500364
365 SRC src{entry, ad, dataIface};
366 EXPECT_TRUE(src.valid());
367
368 ASSERT_TRUE(src.callouts());
369
370 EXPECT_EQ(src.callouts()->callouts().size(), 1);
371
372 auto& callout = src.callouts()->callouts().front();
373
374 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
Matt Spinler717de422020-06-04 13:10:14 -0500375 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500376
377 auto& fru = callout->fruIdentity();
378
379 EXPECT_EQ(fru->getPN().value(), "1234567");
380 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
381 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
382
383 // flatten and unflatten
384 std::vector<uint8_t> data;
385 Stream stream{data};
386 src.flatten(stream);
387
388 stream.offset(0);
389 SRC newSRC{stream};
390 EXPECT_TRUE(newSRC.valid());
391 ASSERT_TRUE(src.callouts());
392 EXPECT_EQ(src.callouts()->callouts().size(), 1);
393}
394
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500395// Test that when the location code can't be obtained that
Matt Spinlered046852020-03-13 13:58:15 -0500396// a procedure callout is used.
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500397TEST_F(SRCTest, InventoryCalloutNoLocCodeTest)
398{
399 message::Entry entry;
400 entry.src.type = 0xBD;
401 entry.src.reasonCode = 0xABCD;
402 entry.subsystem = 0x42;
403 entry.src.powerFault = false;
404
405 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
406 AdditionalData ad{adData};
407 NiceMock<MockDataInterface> dataIface;
408
409 auto func = []() {
410 throw sdbusplus::exception::SdBusError(5, "Error");
411 return std::string{};
412 };
413
414 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
415 .Times(1)
416 .WillOnce(InvokeWithoutArgs(func));
417
418 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
419
420 SRC src{entry, ad, dataIface};
421 EXPECT_TRUE(src.valid());
422
423 ASSERT_TRUE(src.callouts());
424
425 EXPECT_EQ(src.callouts()->callouts().size(), 1);
426
427 auto& callout = src.callouts()->callouts().front();
428 EXPECT_EQ(callout->locationCodeSize(), 0);
Matt Spinler717de422020-06-04 13:10:14 -0500429 EXPECT_EQ(callout->priority(), 'H');
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500430
431 auto& fru = callout->fruIdentity();
432
433 EXPECT_EQ(fru->getMaintProc().value(), "BMCSP01");
434 EXPECT_FALSE(fru->getPN());
435 EXPECT_FALSE(fru->getSN());
436 EXPECT_FALSE(fru->getCCIN());
437
438 // flatten and unflatten
439 std::vector<uint8_t> data;
440 Stream stream{data};
441 src.flatten(stream);
442
443 stream.offset(0);
444 SRC newSRC{stream};
445 EXPECT_TRUE(newSRC.valid());
446 ASSERT_TRUE(src.callouts());
447 EXPECT_EQ(src.callouts()->callouts().size(), 1);
448}
449
450// Test that when the VPD can't be obtained that
451// a callout is still created.
Matt Spinlered046852020-03-13 13:58:15 -0500452TEST_F(SRCTest, InventoryCalloutNoVPDTest)
453{
454 message::Entry entry;
455 entry.src.type = 0xBD;
456 entry.src.reasonCode = 0xABCD;
457 entry.subsystem = 0x42;
458 entry.src.powerFault = false;
459
460 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
461 AdditionalData ad{adData};
462 NiceMock<MockDataInterface> dataIface;
463
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500464 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
465 .Times(1)
466 .WillOnce(Return("UTMS-P10"));
467
Matt Spinlered046852020-03-13 13:58:15 -0500468 auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
469
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500470 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500471 .Times(1)
472 .WillOnce(InvokeWithoutArgs(func));
473
474 SRC src{entry, ad, dataIface};
475 EXPECT_TRUE(src.valid());
Matt Spinlered046852020-03-13 13:58:15 -0500476 ASSERT_TRUE(src.callouts());
Matt Spinlered046852020-03-13 13:58:15 -0500477 EXPECT_EQ(src.callouts()->callouts().size(), 1);
478
479 auto& callout = src.callouts()->callouts().front();
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500480 EXPECT_EQ(callout->locationCode(), "UTMS-P10");
Matt Spinler717de422020-06-04 13:10:14 -0500481 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500482
483 auto& fru = callout->fruIdentity();
484
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500485 EXPECT_EQ(fru->getPN(), "");
486 EXPECT_EQ(fru->getCCIN(), "");
487 EXPECT_EQ(fru->getSN(), "");
488 EXPECT_FALSE(fru->getMaintProc());
489
Matt Spinlered046852020-03-13 13:58:15 -0500490 // flatten and unflatten
491 std::vector<uint8_t> data;
492 Stream stream{data};
493 src.flatten(stream);
494
495 stream.offset(0);
496 SRC newSRC{stream};
497 EXPECT_TRUE(newSRC.valid());
498 ASSERT_TRUE(src.callouts());
499 EXPECT_EQ(src.callouts()->callouts().size(), 1);
500}
Matt Spinler03984582020-04-09 13:17:58 -0500501
502TEST_F(SRCTest, RegistryCalloutTest)
503{
504 message::Entry entry;
505 entry.src.type = 0xBD;
506 entry.src.reasonCode = 0xABCD;
507 entry.subsystem = 0x42;
508 entry.src.powerFault = false;
509
510 entry.callouts = R"(
511 [
512 {
513 "System": "systemA",
514 "CalloutList":
515 [
516 {
517 "Priority": "high",
518 "SymbolicFRU": "service_docs"
519 },
520 {
521 "Priority": "medium",
522 "Procedure": "no_vpd_for_fru"
523 }
524 ]
525 },
526 {
527 "System": "systemB",
528 "CalloutList":
529 [
530 {
531 "Priority": "high",
532 "LocCode": "P0-C8",
533 "SymbolicFRUTrusted": "service_docs"
534 },
535 {
536 "Priority": "medium",
537 "SymbolicFRUTrusted": "service_docs"
538 }
539 ]
Matt Spinleraf191c72020-06-04 11:35:13 -0500540 },
541 {
542 "System": "systemC",
543 "CalloutList":
544 [
545 {
546 "Priority": "high",
547 "LocCode": "P0-C8"
548 },
549 {
550 "Priority": "medium",
551 "LocCode": "P0-C9"
552 }
553 ]
Matt Spinler03984582020-04-09 13:17:58 -0500554 }
555 ])"_json;
556
557 {
558 // Call out a symbolic FRU and a procedure
559 AdditionalData ad;
560 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500561 std::vector<std::string> names{"systemA"};
562
Matt Spinler1ab66962020-10-29 13:21:44 -0500563 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500564
565 SRC src{entry, ad, dataIface};
566
567 auto& callouts = src.callouts()->callouts();
568 ASSERT_EQ(callouts.size(), 2);
569
570 EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
571 EXPECT_EQ(callouts[0]->priority(), 'H');
572
573 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
574 EXPECT_EQ(callouts[1]->priority(), 'M');
575
576 auto& fru1 = callouts[0]->fruIdentity();
577 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
578 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
579 EXPECT_FALSE(fru1->getMaintProc());
580 EXPECT_FALSE(fru1->getSN());
581 EXPECT_FALSE(fru1->getCCIN());
582
583 auto& fru2 = callouts[1]->fruIdentity();
584 EXPECT_EQ(fru2->getMaintProc().value(), "BMCSP01");
585 EXPECT_EQ(fru2->failingComponentType(),
586 src::FRUIdentity::maintenanceProc);
587 EXPECT_FALSE(fru2->getPN());
588 EXPECT_FALSE(fru2->getSN());
589 EXPECT_FALSE(fru2->getCCIN());
590 }
591
592 {
593 // Call out a trusted symbolic FRU with a location code, and
594 // another one without.
595 AdditionalData ad;
596 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500597 std::vector<std::string> names{"systemB"};
598
Matt Spinleraf191c72020-06-04 11:35:13 -0500599 EXPECT_CALL(dataIface, expandLocationCode).WillOnce(Return("P0-C8"));
Matt Spinler1ab66962020-10-29 13:21:44 -0500600 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500601
602 SRC src{entry, ad, dataIface};
603
604 auto& callouts = src.callouts()->callouts();
605 EXPECT_EQ(callouts.size(), 2);
606
607 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
608 EXPECT_EQ(callouts[0]->priority(), 'H');
609
610 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
611 EXPECT_EQ(callouts[1]->priority(), 'M');
612
613 auto& fru1 = callouts[0]->fruIdentity();
614 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
615 EXPECT_EQ(fru1->failingComponentType(),
616 src::FRUIdentity::symbolicFRUTrustedLocCode);
617 EXPECT_FALSE(fru1->getMaintProc());
618 EXPECT_FALSE(fru1->getSN());
619 EXPECT_FALSE(fru1->getCCIN());
620
621 // It asked for a trusted symbolic FRU, but no location code
622 // was provided so it is switched back to a normal one
623 auto& fru2 = callouts[1]->fruIdentity();
624 EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
625 EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
626 EXPECT_FALSE(fru2->getMaintProc());
627 EXPECT_FALSE(fru2->getSN());
628 EXPECT_FALSE(fru2->getCCIN());
629 }
Matt Spinleraf191c72020-06-04 11:35:13 -0500630
631 {
632 // Two hardware callouts
633 AdditionalData ad;
634 NiceMock<MockDataInterface> dataIface;
635 std::vector<std::string> names{"systemC"};
636
Matt Spinler1ab66962020-10-29 13:21:44 -0500637 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinleraf191c72020-06-04 11:35:13 -0500638
639 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
640 .WillOnce(Return("UXXX-P0-C8"));
641
642 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
643 .WillOnce(Return("UXXX-P0-C9"));
644
Matt Spinler2f9225a2020-08-05 12:58:49 -0500645 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C8", 0, false))
Matt Spinleraf191c72020-06-04 11:35:13 -0500646 .WillOnce(Return(
647 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"));
648
Matt Spinler2f9225a2020-08-05 12:58:49 -0500649 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
Matt Spinleraf191c72020-06-04 11:35:13 -0500650 .WillOnce(Return(
651 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"));
652
653 EXPECT_CALL(
654 dataIface,
655 getHWCalloutFields(
656 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _,
657 _))
658 .Times(1)
659 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
660 SetArgReferee<2>("CCCC"),
661 SetArgReferee<3>("123456789ABC")));
662
663 EXPECT_CALL(
664 dataIface,
665 getHWCalloutFields(
666 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1", _, _,
667 _))
668 .Times(1)
669 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
670 SetArgReferee<2>("DDDD"),
671 SetArgReferee<3>("23456789ABCD")));
672
673 SRC src{entry, ad, dataIface};
674
675 auto& callouts = src.callouts()->callouts();
676 EXPECT_EQ(callouts.size(), 2);
677
678 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C8");
679 EXPECT_EQ(callouts[0]->priority(), 'H');
680
681 auto& fru1 = callouts[0]->fruIdentity();
682 EXPECT_EQ(fru1->getPN().value(), "1234567");
683 EXPECT_EQ(fru1->getCCIN().value(), "CCCC");
684 EXPECT_EQ(fru1->getSN().value(), "123456789ABC");
685
686 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C9");
687 EXPECT_EQ(callouts[1]->priority(), 'M');
688
689 auto& fru2 = callouts[1]->fruIdentity();
690 EXPECT_EQ(fru2->getPN().value(), "2345678");
691 EXPECT_EQ(fru2->getCCIN().value(), "DDDD");
692 EXPECT_EQ(fru2->getSN().value(), "23456789ABCD");
693 }
Matt Spinler03984582020-04-09 13:17:58 -0500694}
Matt Spinler717de422020-06-04 13:10:14 -0500695
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500696// Test that a symbolic FRU with a trusted location code callout
697// from the registry can get its location from the
698// CALLOUT_INVENTORY_PATH AdditionalData entry.
699TEST_F(SRCTest, SymbolicFRUWithInvPathTest)
700{
701 message::Entry entry;
702 entry.src.type = 0xBD;
703 entry.src.reasonCode = 0xABCD;
704 entry.subsystem = 0x42;
705 entry.src.powerFault = false;
706
707 entry.callouts = R"(
708 [{
709 "CalloutList":
710 [
711 {
712 "Priority": "high",
713 "SymbolicFRUTrusted": "service_docs",
714 "UseInventoryLocCode": true
715 },
716 {
717 "Priority": "medium",
718 "LocCode": "P0-C8",
719 "SymbolicFRUTrusted": "pwrsply"
720 }
721 ]
722 }])"_json;
723
724 {
725 // The location code for the first symbolic FRU callout will
726 // come from this inventory path since UseInventoryLocCode is set.
727 // In this case there will be no normal FRU callout for the motherboard.
728 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
729 AdditionalData ad{adData};
730 NiceMock<MockDataInterface> dataIface;
731 std::vector<std::string> names{"systemA"};
732
Matt Spinler1ab66962020-10-29 13:21:44 -0500733 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500734
735 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
736 .Times(1)
737 .WillOnce(Return("Ufcs-P10"));
738
739 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
740 .WillOnce(Return("Ufcs-P0-C8"));
741
742 SRC src{entry, ad, dataIface};
743
744 auto& callouts = src.callouts()->callouts();
745 EXPECT_EQ(callouts.size(), 2);
746
747 // The location code for the first symbolic FRU callout with a
748 // trusted location code comes from the motherboard.
749 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P10");
750 EXPECT_EQ(callouts[0]->priority(), 'H');
751 auto& fru1 = callouts[0]->fruIdentity();
752 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
753 EXPECT_EQ(fru1->failingComponentType(),
754 src::FRUIdentity::symbolicFRUTrustedLocCode);
755
756 // The second trusted symbolic FRU callouts uses the location
757 // code in the registry as usual.
758 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P0-C8");
759 EXPECT_EQ(callouts[1]->priority(), 'M');
760 auto& fru2 = callouts[1]->fruIdentity();
761 EXPECT_EQ(fru2->getPN().value(), "PWRSPLY");
762 EXPECT_EQ(fru2->failingComponentType(),
763 src::FRUIdentity::symbolicFRUTrustedLocCode);
764 }
765
766 {
767 // This time say we want to use the location code from
768 // the inventory, but don't pass it in and the callout should
769 // end up a regular symbolic FRU
770 entry.callouts = R"(
771 [{
772 "CalloutList":
773 [
774 {
775 "Priority": "high",
776 "SymbolicFRUTrusted": "service_docs",
777 "UseInventoryLocCode": true
778 }
779 ]
780 }])"_json;
781
782 AdditionalData ad;
783 NiceMock<MockDataInterface> dataIface;
784 std::vector<std::string> names{"systemA"};
785
Matt Spinler1ab66962020-10-29 13:21:44 -0500786 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500787
788 SRC src{entry, ad, dataIface};
789
790 auto& callouts = src.callouts()->callouts();
791 EXPECT_EQ(callouts.size(), 1);
792
793 EXPECT_EQ(callouts[0]->locationCode(), "");
794 EXPECT_EQ(callouts[0]->priority(), 'H');
795 auto& fru1 = callouts[0]->fruIdentity();
796 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
797 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
798 }
799}
800
Matt Spinler717de422020-06-04 13:10:14 -0500801// Test looking up device path fails in the callout jSON.
802TEST_F(SRCTest, DevicePathCalloutTest)
803{
804 message::Entry entry;
805 entry.src.type = 0xBD;
806 entry.src.reasonCode = 0xABCD;
807 entry.subsystem = 0x42;
808 entry.src.powerFault = false;
809
810 const auto calloutJSON = R"(
811 {
812 "I2C":
813 {
814 "14":
815 {
816 "114":
817 {
818 "Callouts":[
819 {
820 "Name": "/chassis/motherboard/cpu0",
821 "LocationCode": "P1-C40",
822 "Priority": "H"
823 },
824 {
825 "Name": "/chassis/motherboard",
826 "LocationCode": "P1",
827 "Priority": "M"
828 },
829 {
830 "Name": "/chassis/motherboard/bmc",
831 "LocationCode": "P1-C15",
832 "Priority": "L"
833 }
834 ],
835 "Dest": "proc 0 target"
836 }
837 }
838 }
839 })";
840
841 auto dataPath = getPELReadOnlyDataPath();
842 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
843 file << calloutJSON;
844 file.close();
845
846 NiceMock<MockDataInterface> dataIface;
847 std::vector<std::string> names{"systemA"};
848
849 EXPECT_CALL(dataIface, getSystemNames)
850 .Times(5)
Matt Spinler1ab66962020-10-29 13:21:44 -0500851 .WillRepeatedly(Return(names));
Matt Spinler717de422020-06-04 13:10:14 -0500852
Matt Spinler2f9225a2020-08-05 12:58:49 -0500853 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500854 .Times(3)
855 .WillRepeatedly(
856 Return("/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"));
857
Matt Spinler2f9225a2020-08-05 12:58:49 -0500858 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500859 .Times(3)
860 .WillRepeatedly(
861 Return("/xyz/openbmc_project/inventory/chassis/motherboard"));
862
Matt Spinler2f9225a2020-08-05 12:58:49 -0500863 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C15", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500864 .Times(3)
865 .WillRepeatedly(
866 Return("/xyz/openbmc_project/inventory/chassis/motherboard/bmc"));
867
868 EXPECT_CALL(dataIface,
869 getLocationCode(
870 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"))
871 .Times(3)
872 .WillRepeatedly(Return("Ufcs-P1-C40"));
873 EXPECT_CALL(
874 dataIface,
875 getLocationCode("/xyz/openbmc_project/inventory/chassis/motherboard"))
876 .Times(3)
877 .WillRepeatedly(Return("Ufcs-P1"));
878 EXPECT_CALL(dataIface,
879 getLocationCode(
880 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc"))
881 .Times(3)
882 .WillRepeatedly(Return("Ufcs-P1-C15"));
883
884 EXPECT_CALL(
885 dataIface,
886 getHWCalloutFields(
887 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _, _))
888 .Times(3)
889 .WillRepeatedly(DoAll(SetArgReferee<1>("1234567"),
890 SetArgReferee<2>("CCCC"),
891 SetArgReferee<3>("123456789ABC")));
892 EXPECT_CALL(
893 dataIface,
894 getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
895 _, _, _))
896 .Times(3)
897 .WillRepeatedly(DoAll(SetArgReferee<1>("7654321"),
898 SetArgReferee<2>("MMMM"),
899 SetArgReferee<3>("CBA987654321")));
900 EXPECT_CALL(
901 dataIface,
902 getHWCalloutFields(
903 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _, _, _))
904 .Times(3)
905 .WillRepeatedly(DoAll(SetArgReferee<1>("7123456"),
906 SetArgReferee<2>("BBBB"),
907 SetArgReferee<3>("C123456789AB")));
908
909 // Call this below with different AdditionalData values that
910 // result in the same callouts.
911 auto checkCallouts = [&entry, &dataIface](const auto& items) {
912 AdditionalData ad{items};
913 SRC src{entry, ad, dataIface};
914
915 ASSERT_TRUE(src.callouts());
916 auto& callouts = src.callouts()->callouts();
917
918 ASSERT_EQ(callouts.size(), 3);
919
920 {
921 EXPECT_EQ(callouts[0]->priority(), 'H');
922 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
923
924 auto& fru = callouts[0]->fruIdentity();
925 EXPECT_EQ(fru->getPN().value(), "1234567");
926 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
927 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
928 }
929 {
930 EXPECT_EQ(callouts[1]->priority(), 'M');
931 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
932
933 auto& fru = callouts[1]->fruIdentity();
934 EXPECT_EQ(fru->getPN().value(), "7654321");
935 EXPECT_EQ(fru->getCCIN().value(), "MMMM");
936 EXPECT_EQ(fru->getSN().value(), "CBA987654321");
937 }
938 {
939 EXPECT_EQ(callouts[2]->priority(), 'L');
940 EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
941
942 auto& fru = callouts[2]->fruIdentity();
943 EXPECT_EQ(fru->getPN().value(), "7123456");
944 EXPECT_EQ(fru->getCCIN().value(), "BBBB");
945 EXPECT_EQ(fru->getSN().value(), "C123456789AB");
946 }
947 };
948
949 {
950 // Callouts based on the device path
951 std::vector<std::string> items{
952 "CALLOUT_ERRNO=5",
953 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
954 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"};
955
956 checkCallouts(items);
957 }
958
959 {
960 // Callouts based on the I2C bus and address
961 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
962 "CALLOUT_IIC_ADDR=0x72"};
963 checkCallouts(items);
964 }
965
966 {
967 // Also based on I2C bus and address, but with bus = /dev/i2c-14
968 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
969 "CALLOUT_IIC_ADDR=0x72"};
970 checkCallouts(items);
971 }
972
973 {
974 // Callout not found
975 std::vector<std::string> items{
976 "CALLOUT_ERRNO=5",
977 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
978 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"};
979
980 AdditionalData ad{items};
981 SRC src{entry, ad, dataIface};
982
983 EXPECT_FALSE(src.callouts());
984 ASSERT_EQ(src.getDebugData().size(), 1);
985 EXPECT_EQ(src.getDebugData()[0],
986 "Problem looking up I2C callouts on 24 18: "
987 "[json.exception.out_of_range.403] key '24' not found");
988 }
989
990 {
991 // Callout not found
992 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=22",
993 "CALLOUT_IIC_ADDR=0x99"};
994 AdditionalData ad{items};
995 SRC src{entry, ad, dataIface};
996
997 EXPECT_FALSE(src.callouts());
998 ASSERT_EQ(src.getDebugData().size(), 1);
999 EXPECT_EQ(src.getDebugData()[0],
1000 "Problem looking up I2C callouts on 22 153: "
1001 "[json.exception.out_of_range.403] key '22' not found");
1002 }
1003
1004 fs::remove_all(dataPath);
1005}
Matt Spinler3bdd0112020-08-27 10:24:34 -05001006
1007// Test when callouts are passed in via JSON
1008TEST_F(SRCTest, JsonCalloutsTest)
1009{
1010 const auto jsonCallouts = R"(
1011 [
1012 {
1013 "LocationCode": "P0-C1",
1014 "Priority": "H",
1015 "MRUs": [
1016 {
1017 "ID": 42,
1018 "Priority": "H"
1019 },
1020 {
1021 "ID": 43,
1022 "Priority": "M"
1023 }
1024 ]
1025 },
1026 {
1027 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
1028 "Priority": "M",
1029 "Guarded": true,
1030 "Deconfigured": true
1031 },
1032 {
1033 "Procedure": "PROCEDU",
1034 "Priority": "A"
1035 },
1036 {
1037 "SymbolicFRU": "TRUSTED",
1038 "Priority": "B",
1039 "TrustedLocationCode": true,
1040 "LocationCode": "P1-C23"
1041 },
1042 {
1043 "SymbolicFRU": "FRUTST1",
1044 "Priority": "C",
1045 "LocationCode": "P1-C24"
1046 },
1047 {
1048 "SymbolicFRU": "FRUTST2LONG",
1049 "Priority": "L"
1050 }
1051 ]
1052 )"_json;
1053
1054 message::Entry entry;
1055 entry.src.type = 0xBD;
1056 entry.src.reasonCode = 0xABCD;
1057 entry.subsystem = 0x42;
1058 entry.src.powerFault = false;
1059
1060 AdditionalData ad;
1061 NiceMock<MockDataInterface> dataIface;
1062
1063 // Callout 0 mock calls
1064 {
1065 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1066 .Times(1)
1067 .WillOnce(Return("UXXX-P0-C1"));
1068 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1069 .Times(1)
1070 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1071 EXPECT_CALL(
1072 dataIface,
1073 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1074 .Times(1)
1075 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1076 SetArgReferee<2>("CCCC"),
1077 SetArgReferee<3>("123456789ABC")));
1078 }
1079 // Callout 1 mock calls
1080 {
1081 EXPECT_CALL(dataIface,
1082 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1083 .WillOnce(Return("UYYY-P5"));
1084 EXPECT_CALL(
1085 dataIface,
1086 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1087 .Times(1)
1088 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
1089 SetArgReferee<2>("DDDD"),
1090 SetArgReferee<3>("23456789ABCD")));
1091 }
1092 // Callout 3 mock calls
1093 {
1094 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1095 .Times(1)
1096 .WillOnce(Return("UXXX-P1-C23"));
1097 }
1098 // Callout 4 mock calls
1099 {
1100 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1101 .Times(1)
1102 .WillOnce(Return("UXXX-P1-C24"));
1103 }
1104
1105 SRC src{entry, ad, jsonCallouts, dataIface};
1106 ASSERT_TRUE(src.callouts());
1107
Matt Spinlerafa2c792020-08-27 11:01:39 -05001108 // Check the guarded and deconfigured flags
1109 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1110
Matt Spinler3bdd0112020-08-27 10:24:34 -05001111 const auto& callouts = src.callouts()->callouts();
1112 ASSERT_EQ(callouts.size(), 6);
1113
1114 // Check callout 0
1115 {
1116 EXPECT_EQ(callouts[0]->priority(), 'H');
1117 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1118
1119 auto& fru = callouts[0]->fruIdentity();
1120 EXPECT_EQ(fru->getPN().value(), "1234567");
1121 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1122 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1123 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001124
1125 auto& mruCallouts = callouts[0]->mru();
1126 ASSERT_TRUE(mruCallouts);
1127 auto& mrus = mruCallouts->mrus();
1128 ASSERT_EQ(mrus.size(), 2);
1129 EXPECT_EQ(mrus[0].id, 42);
1130 EXPECT_EQ(mrus[0].priority, 'H');
1131 EXPECT_EQ(mrus[1].id, 43);
1132 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001133 }
1134
1135 // Check callout 1
1136 {
1137 EXPECT_EQ(callouts[1]->priority(), 'M');
1138 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1139
1140 auto& fru = callouts[1]->fruIdentity();
1141 EXPECT_EQ(fru->getPN().value(), "2345678");
1142 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1143 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1144 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1145 }
1146
1147 // Check callout 2
1148 {
1149 EXPECT_EQ(callouts[2]->priority(), 'A');
1150 EXPECT_EQ(callouts[2]->locationCode(), "");
1151
1152 auto& fru = callouts[2]->fruIdentity();
1153 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1154 EXPECT_EQ(fru->failingComponentType(),
1155 src::FRUIdentity::maintenanceProc);
1156 }
1157
1158 // Check callout 3
1159 {
1160 EXPECT_EQ(callouts[3]->priority(), 'B');
1161 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1162
1163 auto& fru = callouts[3]->fruIdentity();
1164 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1165 EXPECT_EQ(fru->failingComponentType(),
1166 src::FRUIdentity::symbolicFRUTrustedLocCode);
1167 }
1168
1169 // Check callout 4
1170 {
1171 EXPECT_EQ(callouts[4]->priority(), 'C');
1172 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1173
1174 auto& fru = callouts[4]->fruIdentity();
1175 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1176 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1177 }
1178
1179 // Check callout 5
1180 {
1181 EXPECT_EQ(callouts[5]->priority(), 'L');
1182 EXPECT_EQ(callouts[5]->locationCode(), "");
1183
1184 auto& fru = callouts[5]->fruIdentity();
1185 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1186 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1187 }
1188
1189 // Check that it didn't find any errors
1190 const auto& data = src.getDebugData();
1191 EXPECT_TRUE(data.empty());
1192}
1193
1194TEST_F(SRCTest, JsonBadCalloutsTest)
1195{
1196 // The first call will have a Throw in a mock call.
1197 // The second will have a different Throw in a mock call.
1198 // The others have issues with the Priority field.
1199 const auto jsonCallouts = R"(
1200 [
1201 {
1202 "LocationCode": "P0-C1",
1203 "Priority": "H"
1204 },
1205 {
1206 "LocationCode": "P0-C2",
1207 "Priority": "H"
1208 },
1209 {
1210 "LocationCode": "P0-C3"
1211 },
1212 {
1213 "LocationCode": "P0-C4",
1214 "Priority": "X"
1215 }
1216 ]
1217 )"_json;
1218
1219 message::Entry entry;
1220 entry.src.type = 0xBD;
1221 entry.src.reasonCode = 0xABCD;
1222 entry.subsystem = 0x42;
1223 entry.src.powerFault = false;
1224
1225 AdditionalData ad;
1226 NiceMock<MockDataInterface> dataIface;
1227
1228 // Callout 0 mock calls
1229 // Expand location code will fail, so the unexpanded location
1230 // code should show up in the callout instead.
1231 {
1232 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1233 .WillOnce(Throw(std::runtime_error("Fail")));
1234
1235 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1236 .Times(1)
1237 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1238 EXPECT_CALL(
1239 dataIface,
1240 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1241 .Times(1)
1242 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1243 SetArgReferee<2>("CCCC"),
1244 SetArgReferee<3>("123456789ABC")));
1245 }
1246
1247 // Callout 1 mock calls
1248 // getInventoryFromLocCode will fail
1249 {
1250 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1251 .Times(1)
1252 .WillOnce(Return("UXXX-P0-C2"));
1253
1254 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1255 .Times(1)
1256 .WillOnce(Throw(std::runtime_error("Fail")));
1257 }
1258
1259 SRC src{entry, ad, jsonCallouts, dataIface};
1260
1261 ASSERT_TRUE(src.callouts());
1262
1263 const auto& callouts = src.callouts()->callouts();
1264
1265 // Only the first callout was successful
1266 ASSERT_EQ(callouts.size(), 1);
1267
1268 {
1269 EXPECT_EQ(callouts[0]->priority(), 'H');
1270 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
1271
1272 auto& fru = callouts[0]->fruIdentity();
1273 EXPECT_EQ(fru->getPN().value(), "1234567");
1274 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1275 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1276 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1277 }
1278
1279 const auto& data = src.getDebugData();
1280 ASSERT_EQ(data.size(), 4);
1281 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
1282 EXPECT_STREQ(data[1].c_str(),
1283 "Failed extracting callout data from JSON: Unable to "
1284 "get inventory path from location code: P0-C2: Fail");
1285 EXPECT_STREQ(data[2].c_str(),
1286 "Failed extracting callout data from JSON: "
1287 "[json.exception.out_of_range.403] key 'Priority' not found");
1288 EXPECT_STREQ(data[3].c_str(),
1289 "Failed extracting callout data from JSON: Invalid "
1290 "priority 'X' found in JSON callout");
1291}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001292
1293// Test that an inventory path callout can have
1294// a different priority than H.
1295TEST_F(SRCTest, InventoryCalloutTestPriority)
1296{
1297 message::Entry entry;
1298 entry.src.type = 0xBD;
1299 entry.src.reasonCode = 0xABCD;
1300 entry.subsystem = 0x42;
1301 entry.src.powerFault = false;
1302
1303 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard",
1304 "CALLOUT_PRIORITY=M"};
1305 AdditionalData ad{adData};
1306 NiceMock<MockDataInterface> dataIface;
1307
1308 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1309 .WillOnce(Return("UTMS-P1"));
1310
1311 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1312 .Times(1)
1313 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1314 SetArgReferee<3>("123456789ABC")));
1315
1316 SRC src{entry, ad, dataIface};
1317 EXPECT_TRUE(src.valid());
1318
1319 ASSERT_TRUE(src.callouts());
1320
1321 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1322
1323 auto& callout = src.callouts()->callouts().front();
1324
1325 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1326 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001327}