blob: af8d04e895638d9d00280b04996997fb7c35d8b9 [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 Spinler479b6922021-08-17 16:34:59 -0500396// no callout is added.
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
Matt Spinler479b6922021-08-17 16:34:59 -0500423 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500424
425 // flatten and unflatten
426 std::vector<uint8_t> data;
427 Stream stream{data};
428 src.flatten(stream);
429
430 stream.offset(0);
431 SRC newSRC{stream};
432 EXPECT_TRUE(newSRC.valid());
Matt Spinler479b6922021-08-17 16:34:59 -0500433 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500434}
435
436// Test that when the VPD can't be obtained that
437// a callout is still created.
Matt Spinlered046852020-03-13 13:58:15 -0500438TEST_F(SRCTest, InventoryCalloutNoVPDTest)
439{
440 message::Entry entry;
441 entry.src.type = 0xBD;
442 entry.src.reasonCode = 0xABCD;
443 entry.subsystem = 0x42;
444 entry.src.powerFault = false;
445
446 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
447 AdditionalData ad{adData};
448 NiceMock<MockDataInterface> dataIface;
449
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500450 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
451 .Times(1)
452 .WillOnce(Return("UTMS-P10"));
453
Matt Spinlered046852020-03-13 13:58:15 -0500454 auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
455
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500456 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500457 .Times(1)
458 .WillOnce(InvokeWithoutArgs(func));
459
460 SRC src{entry, ad, dataIface};
461 EXPECT_TRUE(src.valid());
Matt Spinlered046852020-03-13 13:58:15 -0500462 ASSERT_TRUE(src.callouts());
Matt Spinlered046852020-03-13 13:58:15 -0500463 EXPECT_EQ(src.callouts()->callouts().size(), 1);
464
465 auto& callout = src.callouts()->callouts().front();
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500466 EXPECT_EQ(callout->locationCode(), "UTMS-P10");
Matt Spinler717de422020-06-04 13:10:14 -0500467 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500468
469 auto& fru = callout->fruIdentity();
470
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500471 EXPECT_EQ(fru->getPN(), "");
472 EXPECT_EQ(fru->getCCIN(), "");
473 EXPECT_EQ(fru->getSN(), "");
474 EXPECT_FALSE(fru->getMaintProc());
475
Matt Spinlered046852020-03-13 13:58:15 -0500476 // flatten and unflatten
477 std::vector<uint8_t> data;
478 Stream stream{data};
479 src.flatten(stream);
480
481 stream.offset(0);
482 SRC newSRC{stream};
483 EXPECT_TRUE(newSRC.valid());
484 ASSERT_TRUE(src.callouts());
485 EXPECT_EQ(src.callouts()->callouts().size(), 1);
486}
Matt Spinler03984582020-04-09 13:17:58 -0500487
488TEST_F(SRCTest, RegistryCalloutTest)
489{
490 message::Entry entry;
491 entry.src.type = 0xBD;
492 entry.src.reasonCode = 0xABCD;
493 entry.subsystem = 0x42;
494 entry.src.powerFault = false;
495
496 entry.callouts = R"(
497 [
498 {
499 "System": "systemA",
500 "CalloutList":
501 [
502 {
503 "Priority": "high",
504 "SymbolicFRU": "service_docs"
505 },
506 {
507 "Priority": "medium",
Matt Spinler479b6922021-08-17 16:34:59 -0500508 "Procedure": "bmc_code"
Matt Spinler03984582020-04-09 13:17:58 -0500509 }
510 ]
511 },
512 {
513 "System": "systemB",
514 "CalloutList":
515 [
516 {
517 "Priority": "high",
518 "LocCode": "P0-C8",
519 "SymbolicFRUTrusted": "service_docs"
520 },
521 {
522 "Priority": "medium",
523 "SymbolicFRUTrusted": "service_docs"
524 }
525 ]
Matt Spinleraf191c72020-06-04 11:35:13 -0500526 },
527 {
528 "System": "systemC",
529 "CalloutList":
530 [
531 {
532 "Priority": "high",
533 "LocCode": "P0-C8"
534 },
535 {
536 "Priority": "medium",
537 "LocCode": "P0-C9"
538 }
539 ]
Matt Spinler03984582020-04-09 13:17:58 -0500540 }
541 ])"_json;
542
543 {
544 // Call out a symbolic FRU and a procedure
545 AdditionalData ad;
546 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500547 std::vector<std::string> names{"systemA"};
548
Matt Spinler1ab66962020-10-29 13:21:44 -0500549 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500550
551 SRC src{entry, ad, dataIface};
552
553 auto& callouts = src.callouts()->callouts();
554 ASSERT_EQ(callouts.size(), 2);
555
556 EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
557 EXPECT_EQ(callouts[0]->priority(), 'H');
558
559 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
560 EXPECT_EQ(callouts[1]->priority(), 'M');
561
562 auto& fru1 = callouts[0]->fruIdentity();
563 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
564 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
565 EXPECT_FALSE(fru1->getMaintProc());
566 EXPECT_FALSE(fru1->getSN());
567 EXPECT_FALSE(fru1->getCCIN());
568
569 auto& fru2 = callouts[1]->fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500570 EXPECT_EQ(fru2->getMaintProc().value(), "BMC0001");
Matt Spinler03984582020-04-09 13:17:58 -0500571 EXPECT_EQ(fru2->failingComponentType(),
572 src::FRUIdentity::maintenanceProc);
573 EXPECT_FALSE(fru2->getPN());
574 EXPECT_FALSE(fru2->getSN());
575 EXPECT_FALSE(fru2->getCCIN());
576 }
577
578 {
579 // Call out a trusted symbolic FRU with a location code, and
580 // another one without.
581 AdditionalData ad;
582 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500583 std::vector<std::string> names{"systemB"};
584
Matt Spinleraf191c72020-06-04 11:35:13 -0500585 EXPECT_CALL(dataIface, expandLocationCode).WillOnce(Return("P0-C8"));
Matt Spinler1ab66962020-10-29 13:21:44 -0500586 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500587
588 SRC src{entry, ad, dataIface};
589
590 auto& callouts = src.callouts()->callouts();
591 EXPECT_EQ(callouts.size(), 2);
592
593 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
594 EXPECT_EQ(callouts[0]->priority(), 'H');
595
596 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
597 EXPECT_EQ(callouts[1]->priority(), 'M');
598
599 auto& fru1 = callouts[0]->fruIdentity();
600 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
601 EXPECT_EQ(fru1->failingComponentType(),
602 src::FRUIdentity::symbolicFRUTrustedLocCode);
603 EXPECT_FALSE(fru1->getMaintProc());
604 EXPECT_FALSE(fru1->getSN());
605 EXPECT_FALSE(fru1->getCCIN());
606
607 // It asked for a trusted symbolic FRU, but no location code
608 // was provided so it is switched back to a normal one
609 auto& fru2 = callouts[1]->fruIdentity();
610 EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
611 EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
612 EXPECT_FALSE(fru2->getMaintProc());
613 EXPECT_FALSE(fru2->getSN());
614 EXPECT_FALSE(fru2->getCCIN());
615 }
Matt Spinleraf191c72020-06-04 11:35:13 -0500616
617 {
618 // Two hardware callouts
619 AdditionalData ad;
620 NiceMock<MockDataInterface> dataIface;
621 std::vector<std::string> names{"systemC"};
622
Matt Spinler1ab66962020-10-29 13:21:44 -0500623 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinleraf191c72020-06-04 11:35:13 -0500624
625 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
626 .WillOnce(Return("UXXX-P0-C8"));
627
628 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
629 .WillOnce(Return("UXXX-P0-C9"));
630
Matt Spinler2f9225a2020-08-05 12:58:49 -0500631 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C8", 0, false))
Matt Spinleraf191c72020-06-04 11:35:13 -0500632 .WillOnce(Return(
633 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"));
634
Matt Spinler2f9225a2020-08-05 12:58:49 -0500635 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
Matt Spinleraf191c72020-06-04 11:35:13 -0500636 .WillOnce(Return(
637 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"));
638
639 EXPECT_CALL(
640 dataIface,
641 getHWCalloutFields(
642 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _,
643 _))
644 .Times(1)
645 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
646 SetArgReferee<2>("CCCC"),
647 SetArgReferee<3>("123456789ABC")));
648
649 EXPECT_CALL(
650 dataIface,
651 getHWCalloutFields(
652 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1", _, _,
653 _))
654 .Times(1)
655 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
656 SetArgReferee<2>("DDDD"),
657 SetArgReferee<3>("23456789ABCD")));
658
659 SRC src{entry, ad, dataIface};
660
661 auto& callouts = src.callouts()->callouts();
662 EXPECT_EQ(callouts.size(), 2);
663
664 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C8");
665 EXPECT_EQ(callouts[0]->priority(), 'H');
666
667 auto& fru1 = callouts[0]->fruIdentity();
668 EXPECT_EQ(fru1->getPN().value(), "1234567");
669 EXPECT_EQ(fru1->getCCIN().value(), "CCCC");
670 EXPECT_EQ(fru1->getSN().value(), "123456789ABC");
671
672 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C9");
673 EXPECT_EQ(callouts[1]->priority(), 'M');
674
675 auto& fru2 = callouts[1]->fruIdentity();
676 EXPECT_EQ(fru2->getPN().value(), "2345678");
677 EXPECT_EQ(fru2->getCCIN().value(), "DDDD");
678 EXPECT_EQ(fru2->getSN().value(), "23456789ABCD");
679 }
Matt Spinler03984582020-04-09 13:17:58 -0500680}
Matt Spinler717de422020-06-04 13:10:14 -0500681
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500682// Test that a symbolic FRU with a trusted location code callout
683// from the registry can get its location from the
684// CALLOUT_INVENTORY_PATH AdditionalData entry.
685TEST_F(SRCTest, SymbolicFRUWithInvPathTest)
686{
687 message::Entry entry;
688 entry.src.type = 0xBD;
689 entry.src.reasonCode = 0xABCD;
690 entry.subsystem = 0x42;
691 entry.src.powerFault = false;
692
693 entry.callouts = R"(
694 [{
695 "CalloutList":
696 [
697 {
698 "Priority": "high",
699 "SymbolicFRUTrusted": "service_docs",
700 "UseInventoryLocCode": true
701 },
702 {
703 "Priority": "medium",
704 "LocCode": "P0-C8",
705 "SymbolicFRUTrusted": "pwrsply"
706 }
707 ]
708 }])"_json;
709
710 {
711 // The location code for the first symbolic FRU callout will
712 // come from this inventory path since UseInventoryLocCode is set.
713 // In this case there will be no normal FRU callout for the motherboard.
714 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
715 AdditionalData ad{adData};
716 NiceMock<MockDataInterface> dataIface;
717 std::vector<std::string> names{"systemA"};
718
Matt Spinler1ab66962020-10-29 13:21:44 -0500719 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500720
721 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
722 .Times(1)
723 .WillOnce(Return("Ufcs-P10"));
724
725 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
726 .WillOnce(Return("Ufcs-P0-C8"));
727
728 SRC src{entry, ad, dataIface};
729
730 auto& callouts = src.callouts()->callouts();
731 EXPECT_EQ(callouts.size(), 2);
732
733 // The location code for the first symbolic FRU callout with a
734 // trusted location code comes from the motherboard.
735 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P10");
736 EXPECT_EQ(callouts[0]->priority(), 'H');
737 auto& fru1 = callouts[0]->fruIdentity();
738 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
739 EXPECT_EQ(fru1->failingComponentType(),
740 src::FRUIdentity::symbolicFRUTrustedLocCode);
741
742 // The second trusted symbolic FRU callouts uses the location
743 // code in the registry as usual.
744 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P0-C8");
745 EXPECT_EQ(callouts[1]->priority(), 'M');
746 auto& fru2 = callouts[1]->fruIdentity();
747 EXPECT_EQ(fru2->getPN().value(), "PWRSPLY");
748 EXPECT_EQ(fru2->failingComponentType(),
749 src::FRUIdentity::symbolicFRUTrustedLocCode);
750 }
751
752 {
753 // This time say we want to use the location code from
754 // the inventory, but don't pass it in and the callout should
755 // end up a regular symbolic FRU
756 entry.callouts = R"(
757 [{
758 "CalloutList":
759 [
760 {
761 "Priority": "high",
762 "SymbolicFRUTrusted": "service_docs",
763 "UseInventoryLocCode": true
764 }
765 ]
766 }])"_json;
767
768 AdditionalData ad;
769 NiceMock<MockDataInterface> dataIface;
770 std::vector<std::string> names{"systemA"};
771
Matt Spinler1ab66962020-10-29 13:21:44 -0500772 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500773
774 SRC src{entry, ad, dataIface};
775
776 auto& callouts = src.callouts()->callouts();
777 EXPECT_EQ(callouts.size(), 1);
778
779 EXPECT_EQ(callouts[0]->locationCode(), "");
780 EXPECT_EQ(callouts[0]->priority(), 'H');
781 auto& fru1 = callouts[0]->fruIdentity();
782 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
783 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
784 }
785}
786
Matt Spinler717de422020-06-04 13:10:14 -0500787// Test looking up device path fails in the callout jSON.
788TEST_F(SRCTest, DevicePathCalloutTest)
789{
790 message::Entry entry;
791 entry.src.type = 0xBD;
792 entry.src.reasonCode = 0xABCD;
793 entry.subsystem = 0x42;
794 entry.src.powerFault = false;
795
796 const auto calloutJSON = R"(
797 {
798 "I2C":
799 {
800 "14":
801 {
802 "114":
803 {
804 "Callouts":[
805 {
806 "Name": "/chassis/motherboard/cpu0",
807 "LocationCode": "P1-C40",
808 "Priority": "H"
809 },
810 {
811 "Name": "/chassis/motherboard",
812 "LocationCode": "P1",
813 "Priority": "M"
814 },
815 {
816 "Name": "/chassis/motherboard/bmc",
817 "LocationCode": "P1-C15",
818 "Priority": "L"
819 }
820 ],
821 "Dest": "proc 0 target"
822 }
823 }
824 }
825 })";
826
827 auto dataPath = getPELReadOnlyDataPath();
828 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
829 file << calloutJSON;
830 file.close();
831
832 NiceMock<MockDataInterface> dataIface;
833 std::vector<std::string> names{"systemA"};
834
835 EXPECT_CALL(dataIface, getSystemNames)
836 .Times(5)
Matt Spinler1ab66962020-10-29 13:21:44 -0500837 .WillRepeatedly(Return(names));
Matt Spinler717de422020-06-04 13:10:14 -0500838
Matt Spinler2f9225a2020-08-05 12:58:49 -0500839 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500840 .Times(3)
841 .WillRepeatedly(
842 Return("/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"));
843
Matt Spinler2f9225a2020-08-05 12:58:49 -0500844 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500845 .Times(3)
846 .WillRepeatedly(
847 Return("/xyz/openbmc_project/inventory/chassis/motherboard"));
848
Matt Spinler2f9225a2020-08-05 12:58:49 -0500849 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C15", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500850 .Times(3)
851 .WillRepeatedly(
852 Return("/xyz/openbmc_project/inventory/chassis/motherboard/bmc"));
853
Matt Spinler0d92b522021-06-16 13:28:17 -0600854 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500855 .Times(3)
856 .WillRepeatedly(Return("Ufcs-P1-C40"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600857
858 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500859 .Times(3)
860 .WillRepeatedly(Return("Ufcs-P1"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600861
862 EXPECT_CALL(dataIface, expandLocationCode("P1-C15", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500863 .Times(3)
864 .WillRepeatedly(Return("Ufcs-P1-C15"));
865
866 EXPECT_CALL(
867 dataIface,
868 getHWCalloutFields(
869 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _, _))
870 .Times(3)
871 .WillRepeatedly(DoAll(SetArgReferee<1>("1234567"),
872 SetArgReferee<2>("CCCC"),
873 SetArgReferee<3>("123456789ABC")));
874 EXPECT_CALL(
875 dataIface,
876 getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
877 _, _, _))
878 .Times(3)
879 .WillRepeatedly(DoAll(SetArgReferee<1>("7654321"),
880 SetArgReferee<2>("MMMM"),
881 SetArgReferee<3>("CBA987654321")));
882 EXPECT_CALL(
883 dataIface,
884 getHWCalloutFields(
885 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _, _, _))
886 .Times(3)
887 .WillRepeatedly(DoAll(SetArgReferee<1>("7123456"),
888 SetArgReferee<2>("BBBB"),
889 SetArgReferee<3>("C123456789AB")));
890
891 // Call this below with different AdditionalData values that
892 // result in the same callouts.
893 auto checkCallouts = [&entry, &dataIface](const auto& items) {
894 AdditionalData ad{items};
895 SRC src{entry, ad, dataIface};
896
897 ASSERT_TRUE(src.callouts());
898 auto& callouts = src.callouts()->callouts();
899
900 ASSERT_EQ(callouts.size(), 3);
901
902 {
903 EXPECT_EQ(callouts[0]->priority(), 'H');
904 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
905
906 auto& fru = callouts[0]->fruIdentity();
907 EXPECT_EQ(fru->getPN().value(), "1234567");
908 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
909 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
910 }
911 {
912 EXPECT_EQ(callouts[1]->priority(), 'M');
913 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
914
915 auto& fru = callouts[1]->fruIdentity();
916 EXPECT_EQ(fru->getPN().value(), "7654321");
917 EXPECT_EQ(fru->getCCIN().value(), "MMMM");
918 EXPECT_EQ(fru->getSN().value(), "CBA987654321");
919 }
920 {
921 EXPECT_EQ(callouts[2]->priority(), 'L');
922 EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
923
924 auto& fru = callouts[2]->fruIdentity();
925 EXPECT_EQ(fru->getPN().value(), "7123456");
926 EXPECT_EQ(fru->getCCIN().value(), "BBBB");
927 EXPECT_EQ(fru->getSN().value(), "C123456789AB");
928 }
929 };
930
931 {
932 // Callouts based on the device path
933 std::vector<std::string> items{
934 "CALLOUT_ERRNO=5",
935 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
936 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"};
937
938 checkCallouts(items);
939 }
940
941 {
942 // Callouts based on the I2C bus and address
943 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
944 "CALLOUT_IIC_ADDR=0x72"};
945 checkCallouts(items);
946 }
947
948 {
949 // Also based on I2C bus and address, but with bus = /dev/i2c-14
950 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
951 "CALLOUT_IIC_ADDR=0x72"};
952 checkCallouts(items);
953 }
954
955 {
956 // Callout not found
957 std::vector<std::string> items{
958 "CALLOUT_ERRNO=5",
959 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
960 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"};
961
962 AdditionalData ad{items};
963 SRC src{entry, ad, dataIface};
964
965 EXPECT_FALSE(src.callouts());
966 ASSERT_EQ(src.getDebugData().size(), 1);
967 EXPECT_EQ(src.getDebugData()[0],
968 "Problem looking up I2C callouts on 24 18: "
969 "[json.exception.out_of_range.403] key '24' not found");
970 }
971
972 {
973 // Callout not found
974 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=22",
975 "CALLOUT_IIC_ADDR=0x99"};
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 22 153: "
983 "[json.exception.out_of_range.403] key '22' not found");
984 }
985
986 fs::remove_all(dataPath);
987}
Matt Spinler3bdd0112020-08-27 10:24:34 -0500988
989// Test when callouts are passed in via JSON
990TEST_F(SRCTest, JsonCalloutsTest)
991{
992 const auto jsonCallouts = R"(
993 [
994 {
995 "LocationCode": "P0-C1",
996 "Priority": "H",
997 "MRUs": [
998 {
999 "ID": 42,
1000 "Priority": "H"
1001 },
1002 {
1003 "ID": 43,
1004 "Priority": "M"
1005 }
1006 ]
1007 },
1008 {
1009 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
1010 "Priority": "M",
1011 "Guarded": true,
1012 "Deconfigured": true
1013 },
1014 {
1015 "Procedure": "PROCEDU",
1016 "Priority": "A"
1017 },
1018 {
1019 "SymbolicFRU": "TRUSTED",
1020 "Priority": "B",
1021 "TrustedLocationCode": true,
1022 "LocationCode": "P1-C23"
1023 },
1024 {
1025 "SymbolicFRU": "FRUTST1",
1026 "Priority": "C",
1027 "LocationCode": "P1-C24"
1028 },
1029 {
1030 "SymbolicFRU": "FRUTST2LONG",
1031 "Priority": "L"
1032 }
1033 ]
1034 )"_json;
1035
1036 message::Entry entry;
1037 entry.src.type = 0xBD;
1038 entry.src.reasonCode = 0xABCD;
1039 entry.subsystem = 0x42;
1040 entry.src.powerFault = false;
1041
1042 AdditionalData ad;
1043 NiceMock<MockDataInterface> dataIface;
1044
1045 // Callout 0 mock calls
1046 {
1047 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1048 .Times(1)
1049 .WillOnce(Return("UXXX-P0-C1"));
1050 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1051 .Times(1)
1052 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1053 EXPECT_CALL(
1054 dataIface,
1055 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1056 .Times(1)
1057 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1058 SetArgReferee<2>("CCCC"),
1059 SetArgReferee<3>("123456789ABC")));
1060 }
1061 // Callout 1 mock calls
1062 {
1063 EXPECT_CALL(dataIface,
1064 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1065 .WillOnce(Return("UYYY-P5"));
1066 EXPECT_CALL(
1067 dataIface,
1068 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1069 .Times(1)
1070 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
1071 SetArgReferee<2>("DDDD"),
1072 SetArgReferee<3>("23456789ABCD")));
1073 }
1074 // Callout 3 mock calls
1075 {
1076 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1077 .Times(1)
1078 .WillOnce(Return("UXXX-P1-C23"));
1079 }
1080 // Callout 4 mock calls
1081 {
1082 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1083 .Times(1)
1084 .WillOnce(Return("UXXX-P1-C24"));
1085 }
1086
1087 SRC src{entry, ad, jsonCallouts, dataIface};
1088 ASSERT_TRUE(src.callouts());
1089
Matt Spinlerafa2c792020-08-27 11:01:39 -05001090 // Check the guarded and deconfigured flags
1091 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1092
Matt Spinler3bdd0112020-08-27 10:24:34 -05001093 const auto& callouts = src.callouts()->callouts();
1094 ASSERT_EQ(callouts.size(), 6);
1095
1096 // Check callout 0
1097 {
1098 EXPECT_EQ(callouts[0]->priority(), 'H');
1099 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1100
1101 auto& fru = callouts[0]->fruIdentity();
1102 EXPECT_EQ(fru->getPN().value(), "1234567");
1103 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1104 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1105 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001106
1107 auto& mruCallouts = callouts[0]->mru();
1108 ASSERT_TRUE(mruCallouts);
1109 auto& mrus = mruCallouts->mrus();
1110 ASSERT_EQ(mrus.size(), 2);
1111 EXPECT_EQ(mrus[0].id, 42);
1112 EXPECT_EQ(mrus[0].priority, 'H');
1113 EXPECT_EQ(mrus[1].id, 43);
1114 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001115 }
1116
1117 // Check callout 1
1118 {
1119 EXPECT_EQ(callouts[1]->priority(), 'M');
1120 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1121
1122 auto& fru = callouts[1]->fruIdentity();
1123 EXPECT_EQ(fru->getPN().value(), "2345678");
1124 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1125 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1126 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1127 }
1128
1129 // Check callout 2
1130 {
1131 EXPECT_EQ(callouts[2]->priority(), 'A');
1132 EXPECT_EQ(callouts[2]->locationCode(), "");
1133
1134 auto& fru = callouts[2]->fruIdentity();
1135 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1136 EXPECT_EQ(fru->failingComponentType(),
1137 src::FRUIdentity::maintenanceProc);
1138 }
1139
1140 // Check callout 3
1141 {
1142 EXPECT_EQ(callouts[3]->priority(), 'B');
1143 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1144
1145 auto& fru = callouts[3]->fruIdentity();
1146 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1147 EXPECT_EQ(fru->failingComponentType(),
1148 src::FRUIdentity::symbolicFRUTrustedLocCode);
1149 }
1150
1151 // Check callout 4
1152 {
1153 EXPECT_EQ(callouts[4]->priority(), 'C');
1154 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1155
1156 auto& fru = callouts[4]->fruIdentity();
1157 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1158 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1159 }
1160
1161 // Check callout 5
1162 {
1163 EXPECT_EQ(callouts[5]->priority(), 'L');
1164 EXPECT_EQ(callouts[5]->locationCode(), "");
1165
1166 auto& fru = callouts[5]->fruIdentity();
1167 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1168 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1169 }
1170
1171 // Check that it didn't find any errors
1172 const auto& data = src.getDebugData();
1173 EXPECT_TRUE(data.empty());
1174}
1175
1176TEST_F(SRCTest, JsonBadCalloutsTest)
1177{
1178 // The first call will have a Throw in a mock call.
1179 // The second will have a different Throw in a mock call.
1180 // The others have issues with the Priority field.
1181 const auto jsonCallouts = R"(
1182 [
1183 {
1184 "LocationCode": "P0-C1",
1185 "Priority": "H"
1186 },
1187 {
1188 "LocationCode": "P0-C2",
1189 "Priority": "H"
1190 },
1191 {
1192 "LocationCode": "P0-C3"
1193 },
1194 {
1195 "LocationCode": "P0-C4",
1196 "Priority": "X"
1197 }
1198 ]
1199 )"_json;
1200
1201 message::Entry entry;
1202 entry.src.type = 0xBD;
1203 entry.src.reasonCode = 0xABCD;
1204 entry.subsystem = 0x42;
1205 entry.src.powerFault = false;
1206
1207 AdditionalData ad;
1208 NiceMock<MockDataInterface> dataIface;
1209
1210 // Callout 0 mock calls
1211 // Expand location code will fail, so the unexpanded location
1212 // code should show up in the callout instead.
1213 {
1214 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1215 .WillOnce(Throw(std::runtime_error("Fail")));
1216
1217 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1218 .Times(1)
1219 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1220 EXPECT_CALL(
1221 dataIface,
1222 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1223 .Times(1)
1224 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1225 SetArgReferee<2>("CCCC"),
1226 SetArgReferee<3>("123456789ABC")));
1227 }
1228
1229 // Callout 1 mock calls
1230 // getInventoryFromLocCode will fail
1231 {
1232 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1233 .Times(1)
1234 .WillOnce(Return("UXXX-P0-C2"));
1235
1236 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1237 .Times(1)
1238 .WillOnce(Throw(std::runtime_error("Fail")));
1239 }
1240
1241 SRC src{entry, ad, jsonCallouts, dataIface};
1242
1243 ASSERT_TRUE(src.callouts());
1244
1245 const auto& callouts = src.callouts()->callouts();
1246
1247 // Only the first callout was successful
1248 ASSERT_EQ(callouts.size(), 1);
1249
1250 {
1251 EXPECT_EQ(callouts[0]->priority(), 'H');
1252 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
1253
1254 auto& fru = callouts[0]->fruIdentity();
1255 EXPECT_EQ(fru->getPN().value(), "1234567");
1256 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1257 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1258 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1259 }
1260
1261 const auto& data = src.getDebugData();
1262 ASSERT_EQ(data.size(), 4);
1263 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
1264 EXPECT_STREQ(data[1].c_str(),
1265 "Failed extracting callout data from JSON: Unable to "
1266 "get inventory path from location code: P0-C2: Fail");
1267 EXPECT_STREQ(data[2].c_str(),
1268 "Failed extracting callout data from JSON: "
1269 "[json.exception.out_of_range.403] key 'Priority' not found");
1270 EXPECT_STREQ(data[3].c_str(),
1271 "Failed extracting callout data from JSON: Invalid "
1272 "priority 'X' found in JSON callout");
1273}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001274
1275// Test that an inventory path callout can have
1276// a different priority than H.
1277TEST_F(SRCTest, InventoryCalloutTestPriority)
1278{
1279 message::Entry entry;
1280 entry.src.type = 0xBD;
1281 entry.src.reasonCode = 0xABCD;
1282 entry.subsystem = 0x42;
1283 entry.src.powerFault = false;
1284
1285 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard",
1286 "CALLOUT_PRIORITY=M"};
1287 AdditionalData ad{adData};
1288 NiceMock<MockDataInterface> dataIface;
1289
1290 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1291 .WillOnce(Return("UTMS-P1"));
1292
1293 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1294 .Times(1)
1295 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1296 SetArgReferee<3>("123456789ABC")));
1297
1298 SRC src{entry, ad, dataIface};
1299 EXPECT_TRUE(src.valid());
1300
1301 ASSERT_TRUE(src.callouts());
1302
1303 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1304
1305 auto& callout = src.callouts()->callouts().front();
1306
1307 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1308 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001309}