blob: 31493780c635d8b5029ffb13d592b043f18cd860 [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
Matt Spinler0d92b522021-06-16 13:28:17 -0600868 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500869 .Times(3)
870 .WillRepeatedly(Return("Ufcs-P1-C40"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600871
872 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500873 .Times(3)
874 .WillRepeatedly(Return("Ufcs-P1"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600875
876 EXPECT_CALL(dataIface, expandLocationCode("P1-C15", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500877 .Times(3)
878 .WillRepeatedly(Return("Ufcs-P1-C15"));
879
880 EXPECT_CALL(
881 dataIface,
882 getHWCalloutFields(
883 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _, _))
884 .Times(3)
885 .WillRepeatedly(DoAll(SetArgReferee<1>("1234567"),
886 SetArgReferee<2>("CCCC"),
887 SetArgReferee<3>("123456789ABC")));
888 EXPECT_CALL(
889 dataIface,
890 getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
891 _, _, _))
892 .Times(3)
893 .WillRepeatedly(DoAll(SetArgReferee<1>("7654321"),
894 SetArgReferee<2>("MMMM"),
895 SetArgReferee<3>("CBA987654321")));
896 EXPECT_CALL(
897 dataIface,
898 getHWCalloutFields(
899 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _, _, _))
900 .Times(3)
901 .WillRepeatedly(DoAll(SetArgReferee<1>("7123456"),
902 SetArgReferee<2>("BBBB"),
903 SetArgReferee<3>("C123456789AB")));
904
905 // Call this below with different AdditionalData values that
906 // result in the same callouts.
907 auto checkCallouts = [&entry, &dataIface](const auto& items) {
908 AdditionalData ad{items};
909 SRC src{entry, ad, dataIface};
910
911 ASSERT_TRUE(src.callouts());
912 auto& callouts = src.callouts()->callouts();
913
914 ASSERT_EQ(callouts.size(), 3);
915
916 {
917 EXPECT_EQ(callouts[0]->priority(), 'H');
918 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
919
920 auto& fru = callouts[0]->fruIdentity();
921 EXPECT_EQ(fru->getPN().value(), "1234567");
922 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
923 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
924 }
925 {
926 EXPECT_EQ(callouts[1]->priority(), 'M');
927 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
928
929 auto& fru = callouts[1]->fruIdentity();
930 EXPECT_EQ(fru->getPN().value(), "7654321");
931 EXPECT_EQ(fru->getCCIN().value(), "MMMM");
932 EXPECT_EQ(fru->getSN().value(), "CBA987654321");
933 }
934 {
935 EXPECT_EQ(callouts[2]->priority(), 'L');
936 EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
937
938 auto& fru = callouts[2]->fruIdentity();
939 EXPECT_EQ(fru->getPN().value(), "7123456");
940 EXPECT_EQ(fru->getCCIN().value(), "BBBB");
941 EXPECT_EQ(fru->getSN().value(), "C123456789AB");
942 }
943 };
944
945 {
946 // Callouts based on the device path
947 std::vector<std::string> items{
948 "CALLOUT_ERRNO=5",
949 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
950 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"};
951
952 checkCallouts(items);
953 }
954
955 {
956 // Callouts based on the I2C bus and address
957 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
958 "CALLOUT_IIC_ADDR=0x72"};
959 checkCallouts(items);
960 }
961
962 {
963 // Also based on I2C bus and address, but with bus = /dev/i2c-14
964 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
965 "CALLOUT_IIC_ADDR=0x72"};
966 checkCallouts(items);
967 }
968
969 {
970 // Callout not found
971 std::vector<std::string> items{
972 "CALLOUT_ERRNO=5",
973 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
974 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"};
975
976 AdditionalData ad{items};
977 SRC src{entry, ad, dataIface};
978
979 EXPECT_FALSE(src.callouts());
980 ASSERT_EQ(src.getDebugData().size(), 1);
981 EXPECT_EQ(src.getDebugData()[0],
982 "Problem looking up I2C callouts on 24 18: "
983 "[json.exception.out_of_range.403] key '24' not found");
984 }
985
986 {
987 // Callout not found
988 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=22",
989 "CALLOUT_IIC_ADDR=0x99"};
990 AdditionalData ad{items};
991 SRC src{entry, ad, dataIface};
992
993 EXPECT_FALSE(src.callouts());
994 ASSERT_EQ(src.getDebugData().size(), 1);
995 EXPECT_EQ(src.getDebugData()[0],
996 "Problem looking up I2C callouts on 22 153: "
997 "[json.exception.out_of_range.403] key '22' not found");
998 }
999
1000 fs::remove_all(dataPath);
1001}
Matt Spinler3bdd0112020-08-27 10:24:34 -05001002
1003// Test when callouts are passed in via JSON
1004TEST_F(SRCTest, JsonCalloutsTest)
1005{
1006 const auto jsonCallouts = R"(
1007 [
1008 {
1009 "LocationCode": "P0-C1",
1010 "Priority": "H",
1011 "MRUs": [
1012 {
1013 "ID": 42,
1014 "Priority": "H"
1015 },
1016 {
1017 "ID": 43,
1018 "Priority": "M"
1019 }
1020 ]
1021 },
1022 {
1023 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
1024 "Priority": "M",
1025 "Guarded": true,
1026 "Deconfigured": true
1027 },
1028 {
1029 "Procedure": "PROCEDU",
1030 "Priority": "A"
1031 },
1032 {
1033 "SymbolicFRU": "TRUSTED",
1034 "Priority": "B",
1035 "TrustedLocationCode": true,
1036 "LocationCode": "P1-C23"
1037 },
1038 {
1039 "SymbolicFRU": "FRUTST1",
1040 "Priority": "C",
1041 "LocationCode": "P1-C24"
1042 },
1043 {
1044 "SymbolicFRU": "FRUTST2LONG",
1045 "Priority": "L"
1046 }
1047 ]
1048 )"_json;
1049
1050 message::Entry entry;
1051 entry.src.type = 0xBD;
1052 entry.src.reasonCode = 0xABCD;
1053 entry.subsystem = 0x42;
1054 entry.src.powerFault = false;
1055
1056 AdditionalData ad;
1057 NiceMock<MockDataInterface> dataIface;
1058
1059 // Callout 0 mock calls
1060 {
1061 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1062 .Times(1)
1063 .WillOnce(Return("UXXX-P0-C1"));
1064 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1065 .Times(1)
1066 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1067 EXPECT_CALL(
1068 dataIface,
1069 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1070 .Times(1)
1071 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1072 SetArgReferee<2>("CCCC"),
1073 SetArgReferee<3>("123456789ABC")));
1074 }
1075 // Callout 1 mock calls
1076 {
1077 EXPECT_CALL(dataIface,
1078 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1079 .WillOnce(Return("UYYY-P5"));
1080 EXPECT_CALL(
1081 dataIface,
1082 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1083 .Times(1)
1084 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
1085 SetArgReferee<2>("DDDD"),
1086 SetArgReferee<3>("23456789ABCD")));
1087 }
1088 // Callout 3 mock calls
1089 {
1090 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1091 .Times(1)
1092 .WillOnce(Return("UXXX-P1-C23"));
1093 }
1094 // Callout 4 mock calls
1095 {
1096 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1097 .Times(1)
1098 .WillOnce(Return("UXXX-P1-C24"));
1099 }
1100
1101 SRC src{entry, ad, jsonCallouts, dataIface};
1102 ASSERT_TRUE(src.callouts());
1103
Matt Spinlerafa2c792020-08-27 11:01:39 -05001104 // Check the guarded and deconfigured flags
1105 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1106
Matt Spinler3bdd0112020-08-27 10:24:34 -05001107 const auto& callouts = src.callouts()->callouts();
1108 ASSERT_EQ(callouts.size(), 6);
1109
1110 // Check callout 0
1111 {
1112 EXPECT_EQ(callouts[0]->priority(), 'H');
1113 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1114
1115 auto& fru = callouts[0]->fruIdentity();
1116 EXPECT_EQ(fru->getPN().value(), "1234567");
1117 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1118 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1119 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001120
1121 auto& mruCallouts = callouts[0]->mru();
1122 ASSERT_TRUE(mruCallouts);
1123 auto& mrus = mruCallouts->mrus();
1124 ASSERT_EQ(mrus.size(), 2);
1125 EXPECT_EQ(mrus[0].id, 42);
1126 EXPECT_EQ(mrus[0].priority, 'H');
1127 EXPECT_EQ(mrus[1].id, 43);
1128 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001129 }
1130
1131 // Check callout 1
1132 {
1133 EXPECT_EQ(callouts[1]->priority(), 'M');
1134 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1135
1136 auto& fru = callouts[1]->fruIdentity();
1137 EXPECT_EQ(fru->getPN().value(), "2345678");
1138 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1139 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1140 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1141 }
1142
1143 // Check callout 2
1144 {
1145 EXPECT_EQ(callouts[2]->priority(), 'A');
1146 EXPECT_EQ(callouts[2]->locationCode(), "");
1147
1148 auto& fru = callouts[2]->fruIdentity();
1149 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1150 EXPECT_EQ(fru->failingComponentType(),
1151 src::FRUIdentity::maintenanceProc);
1152 }
1153
1154 // Check callout 3
1155 {
1156 EXPECT_EQ(callouts[3]->priority(), 'B');
1157 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1158
1159 auto& fru = callouts[3]->fruIdentity();
1160 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1161 EXPECT_EQ(fru->failingComponentType(),
1162 src::FRUIdentity::symbolicFRUTrustedLocCode);
1163 }
1164
1165 // Check callout 4
1166 {
1167 EXPECT_EQ(callouts[4]->priority(), 'C');
1168 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1169
1170 auto& fru = callouts[4]->fruIdentity();
1171 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1172 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1173 }
1174
1175 // Check callout 5
1176 {
1177 EXPECT_EQ(callouts[5]->priority(), 'L');
1178 EXPECT_EQ(callouts[5]->locationCode(), "");
1179
1180 auto& fru = callouts[5]->fruIdentity();
1181 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1182 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1183 }
1184
1185 // Check that it didn't find any errors
1186 const auto& data = src.getDebugData();
1187 EXPECT_TRUE(data.empty());
1188}
1189
1190TEST_F(SRCTest, JsonBadCalloutsTest)
1191{
1192 // The first call will have a Throw in a mock call.
1193 // The second will have a different Throw in a mock call.
1194 // The others have issues with the Priority field.
1195 const auto jsonCallouts = R"(
1196 [
1197 {
1198 "LocationCode": "P0-C1",
1199 "Priority": "H"
1200 },
1201 {
1202 "LocationCode": "P0-C2",
1203 "Priority": "H"
1204 },
1205 {
1206 "LocationCode": "P0-C3"
1207 },
1208 {
1209 "LocationCode": "P0-C4",
1210 "Priority": "X"
1211 }
1212 ]
1213 )"_json;
1214
1215 message::Entry entry;
1216 entry.src.type = 0xBD;
1217 entry.src.reasonCode = 0xABCD;
1218 entry.subsystem = 0x42;
1219 entry.src.powerFault = false;
1220
1221 AdditionalData ad;
1222 NiceMock<MockDataInterface> dataIface;
1223
1224 // Callout 0 mock calls
1225 // Expand location code will fail, so the unexpanded location
1226 // code should show up in the callout instead.
1227 {
1228 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1229 .WillOnce(Throw(std::runtime_error("Fail")));
1230
1231 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1232 .Times(1)
1233 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1234 EXPECT_CALL(
1235 dataIface,
1236 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1237 .Times(1)
1238 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1239 SetArgReferee<2>("CCCC"),
1240 SetArgReferee<3>("123456789ABC")));
1241 }
1242
1243 // Callout 1 mock calls
1244 // getInventoryFromLocCode will fail
1245 {
1246 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1247 .Times(1)
1248 .WillOnce(Return("UXXX-P0-C2"));
1249
1250 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1251 .Times(1)
1252 .WillOnce(Throw(std::runtime_error("Fail")));
1253 }
1254
1255 SRC src{entry, ad, jsonCallouts, dataIface};
1256
1257 ASSERT_TRUE(src.callouts());
1258
1259 const auto& callouts = src.callouts()->callouts();
1260
1261 // Only the first callout was successful
1262 ASSERT_EQ(callouts.size(), 1);
1263
1264 {
1265 EXPECT_EQ(callouts[0]->priority(), 'H');
1266 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
1267
1268 auto& fru = callouts[0]->fruIdentity();
1269 EXPECT_EQ(fru->getPN().value(), "1234567");
1270 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1271 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1272 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1273 }
1274
1275 const auto& data = src.getDebugData();
1276 ASSERT_EQ(data.size(), 4);
1277 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
1278 EXPECT_STREQ(data[1].c_str(),
1279 "Failed extracting callout data from JSON: Unable to "
1280 "get inventory path from location code: P0-C2: Fail");
1281 EXPECT_STREQ(data[2].c_str(),
1282 "Failed extracting callout data from JSON: "
1283 "[json.exception.out_of_range.403] key 'Priority' not found");
1284 EXPECT_STREQ(data[3].c_str(),
1285 "Failed extracting callout data from JSON: Invalid "
1286 "priority 'X' found in JSON callout");
1287}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001288
1289// Test that an inventory path callout can have
1290// a different priority than H.
1291TEST_F(SRCTest, InventoryCalloutTestPriority)
1292{
1293 message::Entry entry;
1294 entry.src.type = 0xBD;
1295 entry.src.reasonCode = 0xABCD;
1296 entry.subsystem = 0x42;
1297 entry.src.powerFault = false;
1298
1299 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard",
1300 "CALLOUT_PRIORITY=M"};
1301 AdditionalData ad{adData};
1302 NiceMock<MockDataInterface> dataIface;
1303
1304 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1305 .WillOnce(Return("UTMS-P1"));
1306
1307 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1308 .Times(1)
1309 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1310 SetArgReferee<3>("123456789ABC")));
1311
1312 SRC src{entry, ad, dataIface};
1313 EXPECT_TRUE(src.valid());
1314
1315 ASSERT_TRUE(src.callouts());
1316
1317 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1318
1319 auto& callout = src.callouts()->callouts().front();
1320
1321 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1322 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001323}