blob: ffe7556d6025f3e5e304b9f28d25f52e53ba9442 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Matt Spinlerf9bae182019-10-09 13:37:38 -05004#include "extensions/openpower-pels/src.hpp"
Matt Spinler075e5ba2020-02-21 15:46:00 -06005#include "mocks.hpp"
Matt Spinlerf9bae182019-10-09 13:37:38 -05006#include "pel_utils.hpp"
7
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +08008#include <fstream>
9
Matt Spinlerf9bae182019-10-09 13:37:38 -050010#include <gtest/gtest.h>
11
12using namespace openpower::pels;
Matt Spinlered046852020-03-13 13:58:15 -050013using ::testing::_;
William A. Kennington IIIb41fa542021-05-29 14:45:16 -070014using ::testing::DoAll;
Matt Spinlered046852020-03-13 13:58:15 -050015using ::testing::InvokeWithoutArgs;
Matt Spinler075e5ba2020-02-21 15:46:00 -060016using ::testing::NiceMock;
17using ::testing::Return;
Matt Spinlered046852020-03-13 13:58:15 -050018using ::testing::SetArgReferee;
Matt Spinler3bdd0112020-08-27 10:24:34 -050019using ::testing::Throw;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080020namespace fs = std::filesystem;
Matt Spinlerf9bae182019-10-09 13:37:38 -050021
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080022const auto testRegistry = R"(
23{
24"PELs":
25[
26 {
27 "Name": "xyz.openbmc_project.Error.Test",
28 "Subsystem": "bmc_firmware",
29 "SRC":
30 {
31 "ReasonCode": "0xABCD",
32 "Words6To9":
33 {
34 "6":
35 {
36 "Description": "Component ID",
37 "AdditionalDataPropSource": "COMPID"
38 },
39 "7":
40 {
41 "Description": "Failure count",
42 "AdditionalDataPropSource": "FREQUENCY"
43 },
44 "8":
45 {
46 "Description": "Time period",
47 "AdditionalDataPropSource": "DURATION"
48 },
49 "9":
50 {
51 "Description": "Error code",
52 "AdditionalDataPropSource": "ERRORCODE"
53 }
54 }
55 },
56 "Documentation":
57 {
58 "Description": "A Component Fault",
59 "Message": "Comp %1 failed %2 times over %3 secs with ErrorCode %4",
60 "MessageArgSources":
61 [
62 "SRCWord6", "SRCWord7", "SRCWord8", "SRCWord9"
63 ]
64 }
65 }
66]
67}
68)";
69
70class SRCTest : public ::testing::Test
71{
72 protected:
73 static void SetUpTestCase()
74 {
75 char path[] = "/tmp/srctestXXXXXX";
76 regDir = mkdtemp(path);
77 }
78
79 static void TearDownTestCase()
80 {
81 fs::remove_all(regDir);
82 }
83
84 static std::string writeData(const char* data)
85 {
86 fs::path path = regDir / "registry.json";
87 std::ofstream stream{path};
88 stream << data;
89 return path;
90 }
91
92 static fs::path regDir;
93};
94
95fs::path SRCTest::regDir{};
96
97TEST_F(SRCTest, UnflattenFlattenTestNoCallouts)
Matt Spinlerf9bae182019-10-09 13:37:38 -050098{
Matt Spinler42828bd2019-10-11 10:39:30 -050099 auto data = pelDataFactory(TestPELType::primarySRCSection);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500100
101 Stream stream{data};
102 SRC src{stream};
103
104 EXPECT_TRUE(src.valid());
105
106 EXPECT_EQ(src.header().id, 0x5053);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600107 EXPECT_EQ(src.header().size, 0x50);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500108 EXPECT_EQ(src.header().version, 0x01);
109 EXPECT_EQ(src.header().subType, 0x01);
110 EXPECT_EQ(src.header().componentID, 0x0202);
111
112 EXPECT_EQ(src.version(), 0x02);
113 EXPECT_EQ(src.flags(), 0x00);
114 EXPECT_EQ(src.hexWordCount(), 9);
115 EXPECT_EQ(src.size(), 0x48);
116
117 const auto& hexwords = src.hexwordData();
Matt Spinlerbd716f02019-10-15 10:54:11 -0500118 EXPECT_EQ(0x02020255, hexwords[0]);
119 EXPECT_EQ(0x03030310, hexwords[1]);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500120 EXPECT_EQ(0x04040404, hexwords[2]);
121 EXPECT_EQ(0x05050505, hexwords[3]);
122 EXPECT_EQ(0x06060606, hexwords[4]);
123 EXPECT_EQ(0x07070707, hexwords[5]);
124 EXPECT_EQ(0x08080808, hexwords[6]);
125 EXPECT_EQ(0x09090909, hexwords[7]);
126
127 EXPECT_EQ(src.asciiString(), "BD8D5678 ");
128 EXPECT_FALSE(src.callouts());
129
130 // Flatten
131 std::vector<uint8_t> newData;
132 Stream newStream{newData};
133
134 src.flatten(newStream);
135 EXPECT_EQ(data, newData);
136}
137
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800138TEST_F(SRCTest, UnflattenFlattenTest2Callouts)
Matt Spinlerf9bae182019-10-09 13:37:38 -0500139{
Matt Spinler42828bd2019-10-11 10:39:30 -0500140 auto data = pelDataFactory(TestPELType::primarySRCSection2Callouts);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500141
142 Stream stream{data};
143 SRC src{stream};
144
145 EXPECT_TRUE(src.valid());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500146 EXPECT_EQ(src.flags(), 0x01); // Additional sections within the SRC.
Matt Spinlerf9bae182019-10-09 13:37:38 -0500147
148 // Spot check the SRC fields, but they're the same as above
149 EXPECT_EQ(src.asciiString(), "BD8D5678 ");
150
151 // There should be 2 callouts
152 const auto& calloutsSection = src.callouts();
153 ASSERT_TRUE(calloutsSection);
154 const auto& callouts = calloutsSection->callouts();
155 EXPECT_EQ(callouts.size(), 2);
156
157 // spot check that each callout has the right substructures
158 EXPECT_TRUE(callouts.front()->fruIdentity());
159 EXPECT_FALSE(callouts.front()->pceIdentity());
160 EXPECT_FALSE(callouts.front()->mru());
161
162 EXPECT_TRUE(callouts.back()->fruIdentity());
163 EXPECT_TRUE(callouts.back()->pceIdentity());
164 EXPECT_TRUE(callouts.back()->mru());
165
166 // Flatten
167 std::vector<uint8_t> newData;
168 Stream newStream{newData};
169
170 src.flatten(newStream);
171 EXPECT_EQ(data, newData);
172}
Matt Spinlerbd716f02019-10-15 10:54:11 -0500173
174// Create an SRC from the message registry
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800175TEST_F(SRCTest, CreateTestNoCallouts)
Matt Spinlerbd716f02019-10-15 10:54:11 -0500176{
177 message::Entry entry;
178 entry.src.type = 0xBD;
179 entry.src.reasonCode = 0xABCD;
180 entry.subsystem = 0x42;
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800181 entry.src.hexwordADFields = {
182 {5, {"TEST1", "DESCR1"}}, // Not a user defined word
183 {6, {"TEST1", "DESCR1"}},
184 {7, {"TEST2", "DESCR2"}},
185 {8, {"TEST3", "DESCR3"}},
186 {9, {"TEST4", "DESCR4"}}};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500187
188 // Values for the SRC words pointed to above
Patrick Williamse5940632024-11-22 20:47:58 -0500189 std::map<std::string, std::string> adData{
190 {"TEST1", "0x12345678"},
191 {"TEST2", "12345678"},
192 {"TEST3", "0XDEF"},
193 {"TEST4", "Z"}};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500194 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600195 NiceMock<MockDataInterface> dataIface;
196
197 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
198
199 SRC src{entry, ad, dataIface};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500200
201 EXPECT_TRUE(src.valid());
Mike Cappsa2d7b772022-03-07 15:47:48 -0500202 EXPECT_FALSE(src.isPowerFaultEvent());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500203 EXPECT_EQ(src.size(), baseSRCSize);
204
205 const auto& hexwords = src.hexwordData();
206
207 // The spec always refers to SRC words 2 - 9, and as the hexwordData()
208 // array index starts at 0 use the math in the [] below to make it easier
209 // to tell what is being accessed.
210 EXPECT_EQ(hexwords[2 - 2] & 0xF0000000, 0); // Partition dump status
211 EXPECT_EQ(hexwords[2 - 2] & 0x00F00000, 0); // Partition boot type
212 EXPECT_EQ(hexwords[2 - 2] & 0x000000FF, 0x55); // SRC format
213 EXPECT_EQ(hexwords[3 - 2] & 0x000000FF, 0x10); // BMC position
Matt Spinler075e5ba2020-02-21 15:46:00 -0600214 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0xABCD0000); // Motherboard CCIN
Matt Spinlerbd716f02019-10-15 10:54:11 -0500215
216 // Validate more fields here as the code starts filling them in.
217
218 // Ensure hex word 5 wasn't allowed to be set to TEST1's contents
Matt Spinler3fe93e92023-04-14 14:06:59 -0500219 // And that none of the error status flags are set
Matt Spinlerbd716f02019-10-15 10:54:11 -0500220 EXPECT_EQ(hexwords[5 - 2], 0);
221
222 // The user defined hex word fields specifed in the additional data.
223 EXPECT_EQ(hexwords[6 - 2], 0x12345678); // TEST1
224 EXPECT_EQ(hexwords[7 - 2], 12345678); // TEST2
225 EXPECT_EQ(hexwords[8 - 2], 0xdef); // TEST3
226 EXPECT_EQ(hexwords[9 - 2], 0); // TEST4, but can't convert a 'Z'
227
228 EXPECT_EQ(src.asciiString(), "BD42ABCD ");
229
230 // No callouts
231 EXPECT_FALSE(src.callouts());
232
233 // May as well spot check the flatten/unflatten
234 std::vector<uint8_t> data;
235 Stream stream{data};
236 src.flatten(stream);
237
238 stream.offset(0);
239 SRC newSRC{stream};
240
241 EXPECT_TRUE(newSRC.valid());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500242 EXPECT_EQ(newSRC.asciiString(), src.asciiString());
243 EXPECT_FALSE(newSRC.callouts());
244}
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800245
Matt Spinler075e5ba2020-02-21 15:46:00 -0600246// Test when the CCIN string isn't a 4 character number
247TEST_F(SRCTest, BadCCINTest)
248{
249 message::Entry entry;
250 entry.src.type = 0xBD;
251 entry.src.reasonCode = 0xABCD;
252 entry.subsystem = 0x42;
Matt Spinler075e5ba2020-02-21 15:46:00 -0600253
Patrick Williamse5940632024-11-22 20:47:58 -0500254 std::map<std::string, std::string> adData{};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600255 AdditionalData ad{adData};
256 NiceMock<MockDataInterface> dataIface;
257
258 // First it isn't a number, then it is too long,
259 // then it is empty.
260 EXPECT_CALL(dataIface, getMotherboardCCIN)
261 .WillOnce(Return("X"))
262 .WillOnce(Return("12345"))
263 .WillOnce(Return(""));
264
265 // The CCIN in the first half should still be 0 each time.
266 {
267 SRC src{entry, ad, dataIface};
268 EXPECT_TRUE(src.valid());
269 const auto& hexwords = src.hexwordData();
270 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
271 }
272
273 {
274 SRC src{entry, ad, dataIface};
275 EXPECT_TRUE(src.valid());
276 const auto& hexwords = src.hexwordData();
277 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
278 }
279
280 {
281 SRC src{entry, ad, dataIface};
282 EXPECT_TRUE(src.valid());
283 const auto& hexwords = src.hexwordData();
284 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
285 }
286}
287
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800288// Test the getErrorDetails function
289TEST_F(SRCTest, MessageSubstitutionTest)
290{
291 auto path = SRCTest::writeData(testRegistry);
292 message::Registry registry{path};
293 auto entry = registry.lookup("0xABCD", message::LookupType::reasonCode);
294
Patrick Williamse5940632024-11-22 20:47:58 -0500295 std::map<std::string, std::string> adData{
296 {"COMPID", "0x1"},
297 {"FREQUENCY", "0x4"},
298 {"DURATION", "30"},
299 {"ERRORCODE", "0x01ABCDEF"}};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800300 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600301 NiceMock<MockDataInterface> dataIface;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800302
Matt Spinler075e5ba2020-02-21 15:46:00 -0600303 SRC src{*entry, ad, dataIface};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800304 EXPECT_TRUE(src.valid());
305
306 auto errorDetails = src.getErrorDetails(registry, DetailLevel::message);
307 ASSERT_TRUE(errorDetails);
Zane Shelley39936e32021-11-13 16:19:34 -0600308 EXPECT_EQ(errorDetails.value(),
309 "Comp 0x00000001 failed 0x00000004 times over 0x0000001E secs "
310 "with ErrorCode 0x01ABCDEF");
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800311}
Matt Spinlered046852020-03-13 13:58:15 -0500312// Test that an inventory path callout string is
313// converted into the appropriate FRU callout.
314TEST_F(SRCTest, InventoryCalloutTest)
315{
316 message::Entry entry;
317 entry.src.type = 0xBD;
318 entry.src.reasonCode = 0xABCD;
319 entry.subsystem = 0x42;
Matt Spinlered046852020-03-13 13:58:15 -0500320
Patrick Williamse5940632024-11-22 20:47:58 -0500321 std::map<std::string, std::string> adData{
322 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinlered046852020-03-13 13:58:15 -0500323 AdditionalData ad{adData};
324 NiceMock<MockDataInterface> dataIface;
325
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500326 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
327 .WillOnce(Return("UTMS-P1"));
328
329 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500330 .Times(1)
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500331 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
332 SetArgReferee<3>("123456789ABC")));
Matt Spinlered046852020-03-13 13:58:15 -0500333
334 SRC src{entry, ad, dataIface};
335 EXPECT_TRUE(src.valid());
336
337 ASSERT_TRUE(src.callouts());
338
339 EXPECT_EQ(src.callouts()->callouts().size(), 1);
340
341 auto& callout = src.callouts()->callouts().front();
342
343 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
Matt Spinler717de422020-06-04 13:10:14 -0500344 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500345
346 auto& fru = callout->fruIdentity();
347
348 EXPECT_EQ(fru->getPN().value(), "1234567");
349 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
350 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
351
352 // flatten and unflatten
353 std::vector<uint8_t> data;
354 Stream stream{data};
355 src.flatten(stream);
356
357 stream.offset(0);
358 SRC newSRC{stream};
359 EXPECT_TRUE(newSRC.valid());
360 ASSERT_TRUE(src.callouts());
361 EXPECT_EQ(src.callouts()->callouts().size(), 1);
362}
363
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500364// Test that when the location code can't be obtained that
Matt Spinler479b6922021-08-17 16:34:59 -0500365// no callout is added.
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500366TEST_F(SRCTest, InventoryCalloutNoLocCodeTest)
367{
368 message::Entry entry;
369 entry.src.type = 0xBD;
370 entry.src.reasonCode = 0xABCD;
371 entry.subsystem = 0x42;
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500372
Patrick Williamse5940632024-11-22 20:47:58 -0500373 std::map<std::string, std::string> adData{
374 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500375 AdditionalData ad{adData};
376 NiceMock<MockDataInterface> dataIface;
377
378 auto func = []() {
379 throw sdbusplus::exception::SdBusError(5, "Error");
380 return std::string{};
381 };
382
383 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
384 .Times(1)
385 .WillOnce(InvokeWithoutArgs(func));
386
387 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
388
389 SRC src{entry, ad, dataIface};
390 EXPECT_TRUE(src.valid());
391
Matt Spinler479b6922021-08-17 16:34:59 -0500392 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500393
394 // flatten and unflatten
395 std::vector<uint8_t> data;
396 Stream stream{data};
397 src.flatten(stream);
398
399 stream.offset(0);
400 SRC newSRC{stream};
401 EXPECT_TRUE(newSRC.valid());
Matt Spinler479b6922021-08-17 16:34:59 -0500402 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500403}
404
405// Test that when the VPD can't be obtained that
406// a callout is still created.
Matt Spinlered046852020-03-13 13:58:15 -0500407TEST_F(SRCTest, InventoryCalloutNoVPDTest)
408{
409 message::Entry entry;
410 entry.src.type = 0xBD;
411 entry.src.reasonCode = 0xABCD;
412 entry.subsystem = 0x42;
Matt Spinlered046852020-03-13 13:58:15 -0500413
Patrick Williamse5940632024-11-22 20:47:58 -0500414 std::map<std::string, std::string> adData{
415 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinlered046852020-03-13 13:58:15 -0500416 AdditionalData ad{adData};
417 NiceMock<MockDataInterface> dataIface;
418
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500419 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
420 .Times(1)
421 .WillOnce(Return("UTMS-P10"));
422
Matt Spinlered046852020-03-13 13:58:15 -0500423 auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
424
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500425 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500426 .Times(1)
427 .WillOnce(InvokeWithoutArgs(func));
428
429 SRC src{entry, ad, dataIface};
430 EXPECT_TRUE(src.valid());
Matt Spinlered046852020-03-13 13:58:15 -0500431 ASSERT_TRUE(src.callouts());
Matt Spinlered046852020-03-13 13:58:15 -0500432 EXPECT_EQ(src.callouts()->callouts().size(), 1);
433
434 auto& callout = src.callouts()->callouts().front();
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500435 EXPECT_EQ(callout->locationCode(), "UTMS-P10");
Matt Spinler717de422020-06-04 13:10:14 -0500436 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500437
438 auto& fru = callout->fruIdentity();
439
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500440 EXPECT_EQ(fru->getPN(), "");
441 EXPECT_EQ(fru->getCCIN(), "");
442 EXPECT_EQ(fru->getSN(), "");
443 EXPECT_FALSE(fru->getMaintProc());
444
Matt Spinlered046852020-03-13 13:58:15 -0500445 // flatten and unflatten
446 std::vector<uint8_t> data;
447 Stream stream{data};
448 src.flatten(stream);
449
450 stream.offset(0);
451 SRC newSRC{stream};
452 EXPECT_TRUE(newSRC.valid());
453 ASSERT_TRUE(src.callouts());
454 EXPECT_EQ(src.callouts()->callouts().size(), 1);
455}
Matt Spinler03984582020-04-09 13:17:58 -0500456
457TEST_F(SRCTest, RegistryCalloutTest)
458{
459 message::Entry entry;
460 entry.src.type = 0xBD;
461 entry.src.reasonCode = 0xABCD;
Matt Spinler3fe93e92023-04-14 14:06:59 -0500462 entry.src.deconfigFlag = true;
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500463 entry.src.checkstopFlag = true;
Matt Spinler03984582020-04-09 13:17:58 -0500464 entry.subsystem = 0x42;
Matt Spinler03984582020-04-09 13:17:58 -0500465
466 entry.callouts = R"(
467 [
468 {
469 "System": "systemA",
470 "CalloutList":
471 [
472 {
473 "Priority": "high",
474 "SymbolicFRU": "service_docs"
475 },
476 {
477 "Priority": "medium",
Matt Spinler2edce4e2024-01-17 11:13:51 -0600478 "Procedure": "BMC0001"
Matt Spinler03984582020-04-09 13:17:58 -0500479 }
480 ]
481 },
482 {
483 "System": "systemB",
484 "CalloutList":
485 [
486 {
487 "Priority": "high",
488 "LocCode": "P0-C8",
489 "SymbolicFRUTrusted": "service_docs"
490 },
491 {
492 "Priority": "medium",
493 "SymbolicFRUTrusted": "service_docs"
494 }
495 ]
Matt Spinleraf191c72020-06-04 11:35:13 -0500496 },
497 {
498 "System": "systemC",
499 "CalloutList":
500 [
501 {
502 "Priority": "high",
503 "LocCode": "P0-C8"
504 },
505 {
506 "Priority": "medium",
507 "LocCode": "P0-C9"
508 }
509 ]
Matt Spinler03984582020-04-09 13:17:58 -0500510 }
511 ])"_json;
512
513 {
514 // Call out a symbolic FRU and a procedure
515 AdditionalData ad;
516 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500517 std::vector<std::string> names{"systemA"};
518
Matt Spinler1ab66962020-10-29 13:21:44 -0500519 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500520
521 SRC src{entry, ad, dataIface};
522
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500523 EXPECT_TRUE(
524 src.getErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured));
525 EXPECT_TRUE(src.getErrorStatusFlag(SRC::ErrorStatusFlags::hwCheckstop));
526
Matt Spinler3fe93e92023-04-14 14:06:59 -0500527 const auto& hexwords = src.hexwordData();
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500528 auto mask = static_cast<uint32_t>(SRC::ErrorStatusFlags::deconfigured) |
529 static_cast<uint32_t>(SRC::ErrorStatusFlags::hwCheckstop);
Matt Spinler3fe93e92023-04-14 14:06:59 -0500530 EXPECT_EQ(hexwords[5 - 2] & mask, mask);
531
Matt Spinler03984582020-04-09 13:17:58 -0500532 auto& callouts = src.callouts()->callouts();
533 ASSERT_EQ(callouts.size(), 2);
534
535 EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
536 EXPECT_EQ(callouts[0]->priority(), 'H');
537
538 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
539 EXPECT_EQ(callouts[1]->priority(), 'M');
540
541 auto& fru1 = callouts[0]->fruIdentity();
542 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
543 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
544 EXPECT_FALSE(fru1->getMaintProc());
545 EXPECT_FALSE(fru1->getSN());
546 EXPECT_FALSE(fru1->getCCIN());
547
548 auto& fru2 = callouts[1]->fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500549 EXPECT_EQ(fru2->getMaintProc().value(), "BMC0001");
Matt Spinler03984582020-04-09 13:17:58 -0500550 EXPECT_EQ(fru2->failingComponentType(),
551 src::FRUIdentity::maintenanceProc);
552 EXPECT_FALSE(fru2->getPN());
553 EXPECT_FALSE(fru2->getSN());
554 EXPECT_FALSE(fru2->getCCIN());
555 }
556
557 {
558 // Call out a trusted symbolic FRU with a location code, and
559 // another one without.
560 AdditionalData ad;
561 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500562 std::vector<std::string> names{"systemB"};
563
Matt Spinleraf191c72020-06-04 11:35:13 -0500564 EXPECT_CALL(dataIface, expandLocationCode).WillOnce(Return("P0-C8"));
Matt Spinler1ab66962020-10-29 13:21:44 -0500565 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500566
567 SRC src{entry, ad, dataIface};
568
569 auto& callouts = src.callouts()->callouts();
570 EXPECT_EQ(callouts.size(), 2);
571
572 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
573 EXPECT_EQ(callouts[0]->priority(), 'H');
574
575 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
576 EXPECT_EQ(callouts[1]->priority(), 'M');
577
578 auto& fru1 = callouts[0]->fruIdentity();
579 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
580 EXPECT_EQ(fru1->failingComponentType(),
581 src::FRUIdentity::symbolicFRUTrustedLocCode);
582 EXPECT_FALSE(fru1->getMaintProc());
583 EXPECT_FALSE(fru1->getSN());
584 EXPECT_FALSE(fru1->getCCIN());
585
586 // It asked for a trusted symbolic FRU, but no location code
587 // was provided so it is switched back to a normal one
588 auto& fru2 = callouts[1]->fruIdentity();
589 EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
590 EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
591 EXPECT_FALSE(fru2->getMaintProc());
592 EXPECT_FALSE(fru2->getSN());
593 EXPECT_FALSE(fru2->getCCIN());
594 }
Matt Spinleraf191c72020-06-04 11:35:13 -0500595
596 {
597 // Two hardware callouts
598 AdditionalData ad;
599 NiceMock<MockDataInterface> dataIface;
600 std::vector<std::string> names{"systemC"};
601
Matt Spinler1ab66962020-10-29 13:21:44 -0500602 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinleraf191c72020-06-04 11:35:13 -0500603
604 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
605 .WillOnce(Return("UXXX-P0-C8"));
606
607 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
608 .WillOnce(Return("UXXX-P0-C9"));
609
Matt Spinler2f9225a2020-08-05 12:58:49 -0500610 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C8", 0, false))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600611 .WillOnce(Return(std::vector<std::string>{
612 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
Matt Spinleraf191c72020-06-04 11:35:13 -0500613
Matt Spinler2f9225a2020-08-05 12:58:49 -0500614 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600615 .WillOnce(Return(std::vector<std::string>{
616 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"}));
Matt Spinleraf191c72020-06-04 11:35:13 -0500617
618 EXPECT_CALL(
619 dataIface,
620 getHWCalloutFields(
621 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _,
622 _))
623 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -0400624 .WillOnce(
625 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
626 SetArgReferee<3>("123456789ABC")));
Matt Spinleraf191c72020-06-04 11:35:13 -0500627
628 EXPECT_CALL(
629 dataIface,
630 getHWCalloutFields(
631 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1", _, _,
632 _))
633 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -0400634 .WillOnce(
635 DoAll(SetArgReferee<1>("2345678"), SetArgReferee<2>("DDDD"),
636 SetArgReferee<3>("23456789ABCD")));
Matt Spinleraf191c72020-06-04 11:35:13 -0500637
638 SRC src{entry, ad, dataIface};
639
640 auto& callouts = src.callouts()->callouts();
641 EXPECT_EQ(callouts.size(), 2);
642
643 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C8");
644 EXPECT_EQ(callouts[0]->priority(), 'H');
645
646 auto& fru1 = callouts[0]->fruIdentity();
647 EXPECT_EQ(fru1->getPN().value(), "1234567");
648 EXPECT_EQ(fru1->getCCIN().value(), "CCCC");
649 EXPECT_EQ(fru1->getSN().value(), "123456789ABC");
650
651 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C9");
652 EXPECT_EQ(callouts[1]->priority(), 'M');
653
654 auto& fru2 = callouts[1]->fruIdentity();
655 EXPECT_EQ(fru2->getPN().value(), "2345678");
656 EXPECT_EQ(fru2->getCCIN().value(), "DDDD");
657 EXPECT_EQ(fru2->getSN().value(), "23456789ABCD");
658 }
Matt Spinler03984582020-04-09 13:17:58 -0500659}
Matt Spinler717de422020-06-04 13:10:14 -0500660
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500661// Test that a symbolic FRU with a trusted location code callout
662// from the registry can get its location from the
663// CALLOUT_INVENTORY_PATH AdditionalData entry.
664TEST_F(SRCTest, SymbolicFRUWithInvPathTest)
665{
666 message::Entry entry;
667 entry.src.type = 0xBD;
668 entry.src.reasonCode = 0xABCD;
669 entry.subsystem = 0x42;
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500670
671 entry.callouts = R"(
672 [{
673 "CalloutList":
674 [
675 {
676 "Priority": "high",
677 "SymbolicFRUTrusted": "service_docs",
678 "UseInventoryLocCode": true
679 },
680 {
681 "Priority": "medium",
682 "LocCode": "P0-C8",
683 "SymbolicFRUTrusted": "pwrsply"
684 }
685 ]
686 }])"_json;
687
688 {
689 // The location code for the first symbolic FRU callout will
690 // come from this inventory path since UseInventoryLocCode is set.
691 // In this case there will be no normal FRU callout for the motherboard.
Patrick Williamse5940632024-11-22 20:47:58 -0500692 std::map<std::string, std::string> adData{
693 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500694 AdditionalData ad{adData};
695 NiceMock<MockDataInterface> dataIface;
696 std::vector<std::string> names{"systemA"};
697
Matt Spinler1ab66962020-10-29 13:21:44 -0500698 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500699
700 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
701 .Times(1)
702 .WillOnce(Return("Ufcs-P10"));
703
704 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
705 .WillOnce(Return("Ufcs-P0-C8"));
706
707 SRC src{entry, ad, dataIface};
708
709 auto& callouts = src.callouts()->callouts();
710 EXPECT_EQ(callouts.size(), 2);
711
712 // The location code for the first symbolic FRU callout with a
713 // trusted location code comes from the motherboard.
714 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P10");
715 EXPECT_EQ(callouts[0]->priority(), 'H');
716 auto& fru1 = callouts[0]->fruIdentity();
717 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
718 EXPECT_EQ(fru1->failingComponentType(),
719 src::FRUIdentity::symbolicFRUTrustedLocCode);
720
721 // The second trusted symbolic FRU callouts uses the location
722 // code in the registry as usual.
723 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P0-C8");
724 EXPECT_EQ(callouts[1]->priority(), 'M');
725 auto& fru2 = callouts[1]->fruIdentity();
726 EXPECT_EQ(fru2->getPN().value(), "PWRSPLY");
727 EXPECT_EQ(fru2->failingComponentType(),
728 src::FRUIdentity::symbolicFRUTrustedLocCode);
729 }
730
731 {
732 // This time say we want to use the location code from
733 // the inventory, but don't pass it in and the callout should
734 // end up a regular symbolic FRU
735 entry.callouts = R"(
736 [{
737 "CalloutList":
738 [
739 {
740 "Priority": "high",
741 "SymbolicFRUTrusted": "service_docs",
742 "UseInventoryLocCode": true
743 }
744 ]
745 }])"_json;
746
747 AdditionalData ad;
748 NiceMock<MockDataInterface> dataIface;
749 std::vector<std::string> names{"systemA"};
750
Matt Spinler1ab66962020-10-29 13:21:44 -0500751 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500752
753 SRC src{entry, ad, dataIface};
754
755 auto& callouts = src.callouts()->callouts();
756 EXPECT_EQ(callouts.size(), 1);
757
758 EXPECT_EQ(callouts[0]->locationCode(), "");
759 EXPECT_EQ(callouts[0]->priority(), 'H');
760 auto& fru1 = callouts[0]->fruIdentity();
761 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
762 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
763 }
764}
765
Matt Spinler7b923722025-03-19 13:17:23 -0500766TEST_F(SRCTest, RegistryCalloutCantGetLocTest)
767{
768 message::Entry entry;
769 entry.src.type = 0xBD;
770 entry.src.reasonCode = 0xABCD;
771 entry.src.deconfigFlag = true;
772 entry.src.checkstopFlag = true;
773 entry.subsystem = 0x42;
774
775 entry.callouts = R"(
776 [{
777 "CalloutList":
778 [
779 {
780 "Priority": "high",
781 "LocCode": "P0-C8"
782 },
783 {
784 "Priority": "medium",
785 "LocCode": "P0-C9"
786 }
787 ]
788 }])"_json;
789
790 {
791 // The calls to expand the location codes will fail, but it should
792 // still create the callouts with the unexpanded values and no HW
793 // fields.
794 AdditionalData ad;
795 NiceMock<MockDataInterface> dataIface;
796 std::vector<std::string> names{"systemC"};
797
798 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
799
800 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
801 .WillRepeatedly(Throw(std::runtime_error("Fail")));
802
803 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
804 .WillRepeatedly(Throw(std::runtime_error("Fail")));
805
806 EXPECT_CALL(dataIface, getInventoryFromLocCode(_, _, _)).Times(0);
807
808 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
809
810 SRC src{entry, ad, dataIface};
811
812 auto& callouts = src.callouts()->callouts();
813 ASSERT_EQ(callouts.size(), 2);
814
815 // Only unexpanded location codes
816 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
817 EXPECT_EQ(callouts[0]->priority(), 'H');
818
819 auto& fru1 = callouts[0]->fruIdentity();
820 EXPECT_EQ(fru1->getPN().value(), "");
821 EXPECT_EQ(fru1->getCCIN().value(), "");
822 EXPECT_EQ(fru1->getSN().value(), "");
823
824 EXPECT_EQ(callouts[1]->locationCode(), "P0-C9");
825 EXPECT_EQ(callouts[1]->priority(), 'M');
826
827 auto& fru2 = callouts[1]->fruIdentity();
828 EXPECT_EQ(fru2->getPN().value(), "");
829 EXPECT_EQ(fru2->getCCIN().value(), "");
830 EXPECT_EQ(fru2->getSN().value(), "");
831 }
832}
833
834TEST_F(SRCTest, TrustedSymbolicFRUCantGetLocTest)
835{
836 message::Entry entry;
837 entry.src.type = 0xBD;
838 entry.src.reasonCode = 0xABCD;
839 entry.subsystem = 0x42;
840
841 entry.callouts = R"(
842 [{
843 "CalloutList":
844 [
845 {
846 "Priority": "medium",
847 "LocCode": "P0-C8",
848 "SymbolicFRUTrusted": "pwrsply"
849 }
850 ]
851 }])"_json;
852
853 std::map<std::string, std::string> adData;
854 AdditionalData ad{adData};
855 NiceMock<MockDataInterface> dataIface;
856 std::vector<std::string> names{"systemA"};
857
858 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
859
860 // The call to expand the location code will fail, but it should
861 // still create the callout with the unexpanded value and the
862 // symbolic FRU can't be trusted.
863 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
864 .WillRepeatedly(Throw(std::runtime_error("Fail")));
865
866 SRC src{entry, ad, dataIface};
867
868 auto& callouts = src.callouts()->callouts();
869 ASSERT_EQ(callouts.size(), 1);
870
871 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
872 EXPECT_EQ(callouts[0]->priority(), 'M');
873 auto& fru = callouts[0]->fruIdentity();
874 EXPECT_EQ(fru->getPN().value(), "PWRSPLY");
875 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
876}
877
Matt Spinler717de422020-06-04 13:10:14 -0500878// Test looking up device path fails in the callout jSON.
879TEST_F(SRCTest, DevicePathCalloutTest)
880{
881 message::Entry entry;
882 entry.src.type = 0xBD;
883 entry.src.reasonCode = 0xABCD;
884 entry.subsystem = 0x42;
Matt Spinler717de422020-06-04 13:10:14 -0500885
886 const auto calloutJSON = R"(
887 {
888 "I2C":
889 {
890 "14":
891 {
892 "114":
893 {
894 "Callouts":[
895 {
896 "Name": "/chassis/motherboard/cpu0",
897 "LocationCode": "P1-C40",
898 "Priority": "H"
899 },
900 {
901 "Name": "/chassis/motherboard",
902 "LocationCode": "P1",
903 "Priority": "M"
904 },
905 {
906 "Name": "/chassis/motherboard/bmc",
907 "LocationCode": "P1-C15",
908 "Priority": "L"
909 }
910 ],
911 "Dest": "proc 0 target"
912 }
913 }
914 }
915 })";
916
917 auto dataPath = getPELReadOnlyDataPath();
918 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
919 file << calloutJSON;
920 file.close();
921
922 NiceMock<MockDataInterface> dataIface;
923 std::vector<std::string> names{"systemA"};
924
925 EXPECT_CALL(dataIface, getSystemNames)
926 .Times(5)
Matt Spinler1ab66962020-10-29 13:21:44 -0500927 .WillRepeatedly(Return(names));
Matt Spinler717de422020-06-04 13:10:14 -0500928
Matt Spinler2f9225a2020-08-05 12:58:49 -0500929 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500930 .Times(3)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600931 .WillRepeatedly(Return(std::vector<std::string>{
932 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
Matt Spinler717de422020-06-04 13:10:14 -0500933
Matt Spinler2f9225a2020-08-05 12:58:49 -0500934 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500935 .Times(3)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600936 .WillRepeatedly(Return(std::vector<std::string>{
937 "/xyz/openbmc_project/inventory/chassis/motherboard"}));
Matt Spinler717de422020-06-04 13:10:14 -0500938
Matt Spinler2f9225a2020-08-05 12:58:49 -0500939 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C15", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500940 .Times(3)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600941 .WillRepeatedly(Return(std::vector<std::string>{
942 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc"}));
Matt Spinler717de422020-06-04 13:10:14 -0500943
Matt Spinler0d92b522021-06-16 13:28:17 -0600944 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500945 .Times(3)
946 .WillRepeatedly(Return("Ufcs-P1-C40"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600947
948 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500949 .Times(3)
950 .WillRepeatedly(Return("Ufcs-P1"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600951
952 EXPECT_CALL(dataIface, expandLocationCode("P1-C15", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500953 .Times(3)
954 .WillRepeatedly(Return("Ufcs-P1-C15"));
955
Patrick Williams075c7922024-08-16 15:19:49 -0400956 EXPECT_CALL(dataIface,
957 getHWCalloutFields(
958 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0",
959 _, _, _))
Matt Spinler717de422020-06-04 13:10:14 -0500960 .Times(3)
Patrick Williams075c7922024-08-16 15:19:49 -0400961 .WillRepeatedly(
962 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
963 SetArgReferee<3>("123456789ABC")));
Matt Spinler717de422020-06-04 13:10:14 -0500964 EXPECT_CALL(
965 dataIface,
966 getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
967 _, _, _))
968 .Times(3)
Patrick Williams075c7922024-08-16 15:19:49 -0400969 .WillRepeatedly(
970 DoAll(SetArgReferee<1>("7654321"), SetArgReferee<2>("MMMM"),
971 SetArgReferee<3>("CBA987654321")));
972 EXPECT_CALL(dataIface,
973 getHWCalloutFields(
974 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _,
975 _, _))
Matt Spinler717de422020-06-04 13:10:14 -0500976 .Times(3)
Patrick Williams075c7922024-08-16 15:19:49 -0400977 .WillRepeatedly(
978 DoAll(SetArgReferee<1>("7123456"), SetArgReferee<2>("BBBB"),
979 SetArgReferee<3>("C123456789AB")));
Matt Spinler717de422020-06-04 13:10:14 -0500980
981 // Call this below with different AdditionalData values that
982 // result in the same callouts.
983 auto checkCallouts = [&entry, &dataIface](const auto& items) {
984 AdditionalData ad{items};
985 SRC src{entry, ad, dataIface};
986
987 ASSERT_TRUE(src.callouts());
988 auto& callouts = src.callouts()->callouts();
989
990 ASSERT_EQ(callouts.size(), 3);
991
992 {
993 EXPECT_EQ(callouts[0]->priority(), 'H');
994 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
995
996 auto& fru = callouts[0]->fruIdentity();
997 EXPECT_EQ(fru->getPN().value(), "1234567");
998 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
999 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1000 }
1001 {
1002 EXPECT_EQ(callouts[1]->priority(), 'M');
1003 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
1004
1005 auto& fru = callouts[1]->fruIdentity();
1006 EXPECT_EQ(fru->getPN().value(), "7654321");
1007 EXPECT_EQ(fru->getCCIN().value(), "MMMM");
1008 EXPECT_EQ(fru->getSN().value(), "CBA987654321");
1009 }
1010 {
1011 EXPECT_EQ(callouts[2]->priority(), 'L');
1012 EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
1013
1014 auto& fru = callouts[2]->fruIdentity();
1015 EXPECT_EQ(fru->getPN().value(), "7123456");
1016 EXPECT_EQ(fru->getCCIN().value(), "BBBB");
1017 EXPECT_EQ(fru->getSN().value(), "C123456789AB");
1018 }
1019 };
1020
1021 {
1022 // Callouts based on the device path
Patrick Williamse5940632024-11-22 20:47:58 -05001023 std::map<std::string, std::string> items{
1024 {"CALLOUT_ERRNO", "5"},
1025 {"CALLOUT_DEVICE_PATH",
1026 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
Matt Spinler717de422020-06-04 13:10:14 -05001027
1028 checkCallouts(items);
1029 }
1030
1031 {
1032 // Callouts based on the I2C bus and address
Patrick Williamse5940632024-11-22 20:47:58 -05001033 std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1034 {"CALLOUT_IIC_BUS", "14"},
1035 {"CALLOUT_IIC_ADDR", "0x72"}};
Matt Spinler717de422020-06-04 13:10:14 -05001036 checkCallouts(items);
1037 }
1038
1039 {
1040 // Also based on I2C bus and address, but with bus = /dev/i2c-14
Patrick Williamse5940632024-11-22 20:47:58 -05001041 std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1042 {"CALLOUT_IIC_BUS", "14"},
1043 {"CALLOUT_IIC_ADDR", "0x72"}};
Matt Spinler717de422020-06-04 13:10:14 -05001044 checkCallouts(items);
1045 }
1046
1047 {
1048 // Callout not found
Patrick Williamse5940632024-11-22 20:47:58 -05001049 std::map<std::string, std::string> items{
1050 {"CALLOUT_ERRNO", "5"},
1051 {"CALLOUT_DEVICE_PATH",
1052 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"}};
Matt Spinler717de422020-06-04 13:10:14 -05001053
1054 AdditionalData ad{items};
1055 SRC src{entry, ad, dataIface};
1056
1057 EXPECT_FALSE(src.callouts());
1058 ASSERT_EQ(src.getDebugData().size(), 1);
1059 EXPECT_EQ(src.getDebugData()[0],
1060 "Problem looking up I2C callouts on 24 18: "
1061 "[json.exception.out_of_range.403] key '24' not found");
1062 }
1063
1064 {
1065 // Callout not found
Patrick Williamse5940632024-11-22 20:47:58 -05001066 std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1067 {"CALLOUT_IIC_BUS", "22"},
1068 {"CALLOUT_IIC_ADDR", "0x99"}};
Matt Spinler717de422020-06-04 13:10:14 -05001069 AdditionalData ad{items};
1070 SRC src{entry, ad, dataIface};
1071
1072 EXPECT_FALSE(src.callouts());
1073 ASSERT_EQ(src.getDebugData().size(), 1);
1074 EXPECT_EQ(src.getDebugData()[0],
1075 "Problem looking up I2C callouts on 22 153: "
1076 "[json.exception.out_of_range.403] key '22' not found");
1077 }
Matt Spinler7b923722025-03-19 13:17:23 -05001078}
1079
1080TEST_F(SRCTest, DevicePathCantGetLocTest)
1081{
1082 message::Entry entry;
1083 entry.src.type = 0xBD;
1084 entry.src.reasonCode = 0xABCD;
1085 entry.subsystem = 0x42;
1086
1087 const auto calloutJSON = R"(
1088 {
1089 "I2C":
1090 {
1091 "14":
1092 {
1093 "114":
1094 {
1095 "Callouts":[
1096 {
1097 "Name": "/chassis/motherboard/cpu0",
1098 "LocationCode": "P1-C40",
1099 "Priority": "H"
1100 },
1101 {
1102 "Name": "/chassis/motherboard",
1103 "LocationCode": "P1",
1104 "Priority": "M"
1105 }
1106 ],
1107 "Dest": "proc 0 target"
1108 }
1109 }
1110 }
1111 })";
1112
1113 auto dataPath = getPELReadOnlyDataPath();
1114 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
1115 file << calloutJSON;
1116 file.close();
1117
1118 NiceMock<MockDataInterface> dataIface;
1119 std::vector<std::string> names{"systemA"};
1120
1121 EXPECT_CALL(dataIface, getSystemNames).WillRepeatedly(Return(names));
1122
1123 // The calls to expand the location codes will fail, so still create
1124 // the callouts with the unexpanded values and no HW fields
1125
1126 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
1127 .WillRepeatedly(Throw(std::runtime_error("Fail")));
1128
1129 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
1130 .WillRepeatedly(Throw(std::runtime_error("Fail")));
1131
1132 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
1133 .Times(0);
1134 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false)).Times(0);
1135
1136 std::map<std::string, std::string> items{
1137 {"CALLOUT_ERRNO", "5"},
1138 {"CALLOUT_DEVICE_PATH",
1139 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
1140
1141 AdditionalData ad{items};
1142 SRC src{entry, ad, dataIface};
1143
1144 ASSERT_TRUE(src.callouts());
1145 auto& callouts = src.callouts()->callouts();
1146
1147 ASSERT_EQ(callouts.size(), 2);
1148
1149 // Should just contain the unexpanded location codes
1150 {
1151 EXPECT_EQ(callouts[0]->priority(), 'H');
1152 EXPECT_EQ(callouts[0]->locationCode(), "P1-C40");
1153
1154 auto& fru = callouts[0]->fruIdentity();
1155 EXPECT_EQ(fru->getPN().value(), "");
1156 EXPECT_EQ(fru->getCCIN().value(), "");
1157 EXPECT_EQ(fru->getSN().value(), "");
1158 }
1159 {
1160 EXPECT_EQ(callouts[1]->priority(), 'M');
1161 EXPECT_EQ(callouts[1]->locationCode(), "P1");
1162
1163 auto& fru = callouts[1]->fruIdentity();
1164 EXPECT_EQ(fru->getPN().value(), "");
1165 EXPECT_EQ(fru->getCCIN().value(), "");
1166 EXPECT_EQ(fru->getSN().value(), "");
1167 }
Matt Spinler717de422020-06-04 13:10:14 -05001168
1169 fs::remove_all(dataPath);
1170}
Matt Spinler3bdd0112020-08-27 10:24:34 -05001171
1172// Test when callouts are passed in via JSON
1173TEST_F(SRCTest, JsonCalloutsTest)
1174{
1175 const auto jsonCallouts = R"(
1176 [
1177 {
1178 "LocationCode": "P0-C1",
1179 "Priority": "H",
1180 "MRUs": [
1181 {
1182 "ID": 42,
1183 "Priority": "H"
1184 },
1185 {
1186 "ID": 43,
1187 "Priority": "M"
1188 }
1189 ]
1190 },
1191 {
1192 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
1193 "Priority": "M",
1194 "Guarded": true,
1195 "Deconfigured": true
1196 },
1197 {
1198 "Procedure": "PROCEDU",
1199 "Priority": "A"
1200 },
1201 {
1202 "SymbolicFRU": "TRUSTED",
1203 "Priority": "B",
1204 "TrustedLocationCode": true,
1205 "LocationCode": "P1-C23"
1206 },
1207 {
1208 "SymbolicFRU": "FRUTST1",
1209 "Priority": "C",
1210 "LocationCode": "P1-C24"
1211 },
1212 {
1213 "SymbolicFRU": "FRUTST2LONG",
1214 "Priority": "L"
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001215 },
1216 {
1217 "Procedure": "fsi_path",
1218 "Priority": "L"
1219 },
1220 {
1221 "SymbolicFRU": "ambient_temp",
1222 "Priority": "L"
Matt Spinler3bdd0112020-08-27 10:24:34 -05001223 }
1224 ]
1225 )"_json;
1226
1227 message::Entry entry;
1228 entry.src.type = 0xBD;
1229 entry.src.reasonCode = 0xABCD;
1230 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001231
1232 AdditionalData ad;
1233 NiceMock<MockDataInterface> dataIface;
1234
1235 // Callout 0 mock calls
1236 {
1237 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1238 .Times(1)
1239 .WillOnce(Return("UXXX-P0-C1"));
1240 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1241 .Times(1)
Matt Spinlerbad056b2023-01-25 14:16:57 -06001242 .WillOnce(Return(std::vector<std::string>{
1243 "/inv/system/chassis/motherboard/bmc"}));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001244 EXPECT_CALL(
1245 dataIface,
1246 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1247 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -04001248 .WillOnce(
1249 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1250 SetArgReferee<3>("123456789ABC")));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001251 }
1252 // Callout 1 mock calls
1253 {
1254 EXPECT_CALL(dataIface,
1255 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1256 .WillOnce(Return("UYYY-P5"));
1257 EXPECT_CALL(
1258 dataIface,
1259 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1260 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -04001261 .WillOnce(
1262 DoAll(SetArgReferee<1>("2345678"), SetArgReferee<2>("DDDD"),
1263 SetArgReferee<3>("23456789ABCD")));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001264 }
1265 // Callout 3 mock calls
1266 {
1267 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1268 .Times(1)
1269 .WillOnce(Return("UXXX-P1-C23"));
1270 }
1271 // Callout 4 mock calls
1272 {
1273 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1274 .Times(1)
1275 .WillOnce(Return("UXXX-P1-C24"));
1276 }
1277
1278 SRC src{entry, ad, jsonCallouts, dataIface};
1279 ASSERT_TRUE(src.callouts());
1280
Matt Spinlerafa2c792020-08-27 11:01:39 -05001281 // Check the guarded and deconfigured flags
1282 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1283
Matt Spinler3bdd0112020-08-27 10:24:34 -05001284 const auto& callouts = src.callouts()->callouts();
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001285 ASSERT_EQ(callouts.size(), 8);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001286
1287 // Check callout 0
1288 {
1289 EXPECT_EQ(callouts[0]->priority(), 'H');
1290 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1291
1292 auto& fru = callouts[0]->fruIdentity();
1293 EXPECT_EQ(fru->getPN().value(), "1234567");
1294 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1295 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1296 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001297
1298 auto& mruCallouts = callouts[0]->mru();
1299 ASSERT_TRUE(mruCallouts);
1300 auto& mrus = mruCallouts->mrus();
1301 ASSERT_EQ(mrus.size(), 2);
1302 EXPECT_EQ(mrus[0].id, 42);
1303 EXPECT_EQ(mrus[0].priority, 'H');
1304 EXPECT_EQ(mrus[1].id, 43);
1305 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001306 }
1307
1308 // Check callout 1
1309 {
1310 EXPECT_EQ(callouts[1]->priority(), 'M');
1311 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1312
1313 auto& fru = callouts[1]->fruIdentity();
1314 EXPECT_EQ(fru->getPN().value(), "2345678");
1315 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1316 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1317 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1318 }
1319
1320 // Check callout 2
1321 {
1322 EXPECT_EQ(callouts[2]->priority(), 'A');
1323 EXPECT_EQ(callouts[2]->locationCode(), "");
1324
1325 auto& fru = callouts[2]->fruIdentity();
1326 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1327 EXPECT_EQ(fru->failingComponentType(),
1328 src::FRUIdentity::maintenanceProc);
1329 }
1330
1331 // Check callout 3
1332 {
1333 EXPECT_EQ(callouts[3]->priority(), 'B');
1334 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1335
1336 auto& fru = callouts[3]->fruIdentity();
1337 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1338 EXPECT_EQ(fru->failingComponentType(),
1339 src::FRUIdentity::symbolicFRUTrustedLocCode);
1340 }
1341
1342 // Check callout 4
1343 {
1344 EXPECT_EQ(callouts[4]->priority(), 'C');
1345 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1346
1347 auto& fru = callouts[4]->fruIdentity();
1348 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1349 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1350 }
1351
1352 // Check callout 5
1353 {
1354 EXPECT_EQ(callouts[5]->priority(), 'L');
1355 EXPECT_EQ(callouts[5]->locationCode(), "");
1356
1357 auto& fru = callouts[5]->fruIdentity();
1358 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1359 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1360 }
1361
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001362 // Check callout 6
1363 {
1364 EXPECT_EQ(callouts[6]->priority(), 'L');
1365 EXPECT_EQ(callouts[6]->locationCode(), "");
1366
1367 auto& fru = callouts[6]->fruIdentity();
1368 EXPECT_EQ(fru->getMaintProc().value(), "BMC0004");
1369 EXPECT_EQ(fru->failingComponentType(),
1370 src::FRUIdentity::maintenanceProc);
1371 }
1372
1373 // Check callout 7
1374 {
1375 EXPECT_EQ(callouts[7]->priority(), 'L');
1376 EXPECT_EQ(callouts[7]->locationCode(), "");
1377
1378 auto& fru = callouts[7]->fruIdentity();
1379 EXPECT_EQ(fru->getPN().value(), "AMBTEMP");
1380 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1381 }
1382
Matt Spinler3bdd0112020-08-27 10:24:34 -05001383 // Check that it didn't find any errors
1384 const auto& data = src.getDebugData();
1385 EXPECT_TRUE(data.empty());
1386}
1387
1388TEST_F(SRCTest, JsonBadCalloutsTest)
1389{
1390 // The first call will have a Throw in a mock call.
1391 // The second will have a different Throw in a mock call.
1392 // The others have issues with the Priority field.
1393 const auto jsonCallouts = R"(
1394 [
1395 {
1396 "LocationCode": "P0-C1",
1397 "Priority": "H"
1398 },
1399 {
1400 "LocationCode": "P0-C2",
1401 "Priority": "H"
1402 },
1403 {
1404 "LocationCode": "P0-C3"
1405 },
1406 {
1407 "LocationCode": "P0-C4",
1408 "Priority": "X"
1409 }
1410 ]
1411 )"_json;
1412
1413 message::Entry entry;
1414 entry.src.type = 0xBD;
1415 entry.src.reasonCode = 0xABCD;
1416 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001417
1418 AdditionalData ad;
1419 NiceMock<MockDataInterface> dataIface;
1420
1421 // Callout 0 mock calls
1422 // Expand location code will fail, so the unexpanded location
1423 // code should show up in the callout instead.
1424 {
1425 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1426 .WillOnce(Throw(std::runtime_error("Fail")));
1427
1428 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1429 .Times(1)
Matt Spinlerbad056b2023-01-25 14:16:57 -06001430 .WillOnce(Return(std::vector<std::string>{
1431 "/inv/system/chassis/motherboard/bmc"}));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001432 EXPECT_CALL(
1433 dataIface,
1434 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1435 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -04001436 .WillOnce(
1437 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1438 SetArgReferee<3>("123456789ABC")));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001439 }
1440
1441 // Callout 1 mock calls
Matt Spinler7b923722025-03-19 13:17:23 -05001442 // getInventoryFromLocCode will fail, so a callout with just the
1443 // location code will be created.
Matt Spinler3bdd0112020-08-27 10:24:34 -05001444 {
1445 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1446 .Times(1)
1447 .WillOnce(Return("UXXX-P0-C2"));
1448
1449 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1450 .Times(1)
1451 .WillOnce(Throw(std::runtime_error("Fail")));
1452 }
1453
1454 SRC src{entry, ad, jsonCallouts, dataIface};
1455
1456 ASSERT_TRUE(src.callouts());
1457
1458 const auto& callouts = src.callouts()->callouts();
1459
Matt Spinler7b923722025-03-19 13:17:23 -05001460 // The first callout will have the unexpanded location code.
1461 ASSERT_EQ(callouts.size(), 2);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001462
Matt Spinler7b923722025-03-19 13:17:23 -05001463 EXPECT_EQ(callouts[0]->priority(), 'H');
1464 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
Matt Spinler3bdd0112020-08-27 10:24:34 -05001465
Matt Spinler7b923722025-03-19 13:17:23 -05001466 auto& fru0 = callouts[0]->fruIdentity();
1467 EXPECT_EQ(fru0->getPN().value(), "1234567");
1468 EXPECT_EQ(fru0->getCCIN().value(), "CCCC");
1469 EXPECT_EQ(fru0->getSN().value(), "123456789ABC");
1470 EXPECT_EQ(fru0->failingComponentType(), src::FRUIdentity::hardwareFRU);
1471
1472 // The second callout will have empty HW details.
1473 EXPECT_EQ(callouts[1]->priority(), 'H');
1474 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C2");
1475
1476 auto& fru1 = callouts[1]->fruIdentity();
1477 EXPECT_EQ(fru1->getPN().value(), "");
1478 EXPECT_EQ(fru1->getCCIN().value(), "");
1479 EXPECT_EQ(fru1->getSN().value(), "");
1480 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001481
1482 const auto& data = src.getDebugData();
1483 ASSERT_EQ(data.size(), 4);
1484 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
Matt Spinler7b923722025-03-19 13:17:23 -05001485 EXPECT_STREQ(
1486 data[1].c_str(),
1487 "Unable to get inventory path from location code: P0-C2: Fail");
Matt Spinler3bdd0112020-08-27 10:24:34 -05001488 EXPECT_STREQ(data[2].c_str(),
1489 "Failed extracting callout data from JSON: "
1490 "[json.exception.out_of_range.403] key 'Priority' not found");
1491 EXPECT_STREQ(data[3].c_str(),
1492 "Failed extracting callout data from JSON: Invalid "
1493 "priority 'X' found in JSON callout");
1494}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001495
1496// Test that an inventory path callout can have
1497// a different priority than H.
1498TEST_F(SRCTest, InventoryCalloutTestPriority)
1499{
1500 message::Entry entry;
1501 entry.src.type = 0xBD;
1502 entry.src.reasonCode = 0xABCD;
1503 entry.subsystem = 0x42;
Miguel Gomez53ef1552020-10-14 21:16:32 +00001504
Patrick Williamse5940632024-11-22 20:47:58 -05001505 std::map<std::string, std::string> adData{
1506 {"CALLOUT_INVENTORY_PATH", "motherboard"}, {"CALLOUT_PRIORITY", "M"}};
Miguel Gomez53ef1552020-10-14 21:16:32 +00001507 AdditionalData ad{adData};
1508 NiceMock<MockDataInterface> dataIface;
1509
1510 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1511 .WillOnce(Return("UTMS-P1"));
1512
1513 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1514 .Times(1)
1515 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1516 SetArgReferee<3>("123456789ABC")));
1517
1518 SRC src{entry, ad, dataIface};
1519 EXPECT_TRUE(src.valid());
1520
1521 ASSERT_TRUE(src.callouts());
1522
1523 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1524
1525 auto& callout = src.callouts()->callouts().front();
1526
1527 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1528 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001529}
Sumit Kumar9d43a722021-08-24 09:46:19 -05001530
Sumit Kumar50bfa692022-01-06 06:48:26 -06001531// Test SRC with additional data - PEL_SUBSYSTEM
1532TEST_F(SRCTest, TestPELSubsystem)
1533{
1534 message::Entry entry;
1535 entry.src.type = 0xBD;
1536 entry.src.reasonCode = 0xABCD;
1537 entry.subsystem = 0x42;
Sumit Kumar50bfa692022-01-06 06:48:26 -06001538
1539 // Values for the SRC words pointed to above
Patrick Williamse5940632024-11-22 20:47:58 -05001540 std::map<std::string, std::string> adData{{"PEL_SUBSYSTEM", "0x20"}};
Sumit Kumar50bfa692022-01-06 06:48:26 -06001541 AdditionalData ad{adData};
1542 NiceMock<MockDataInterface> dataIface;
1543
1544 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
1545
Sumit Kumar50bfa692022-01-06 06:48:26 -06001546 SRC src{entry, ad, dataIface};
1547
1548 EXPECT_TRUE(src.valid());
1549
1550 EXPECT_EQ(src.asciiString(), "BD20ABCD ");
1551}
Vijay Lobo875b6c72021-10-20 17:38:56 -05001552
1553void setAsciiString(std::vector<uint8_t>& src, const std::string& value)
1554{
1555 assert(40 + value.size() <= src.size());
1556
1557 for (size_t i = 0; i < value.size(); i++)
1558 {
1559 src[40 + i] = value[i];
1560 }
1561}
1562
1563TEST_F(SRCTest, TestGetProgressCode)
1564{
1565 {
1566 // A real SRC with CC009184
1567 std::vector<uint8_t> src{
1568 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1569 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1570 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1571 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1572 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1573
1574 EXPECT_EQ(SRC::getProgressCode(src), 0xCC009184);
1575 }
1576
1577 {
1578 // A real SRC with STANDBY
1579 std::vector<uint8_t> src{
1580 2, 0, 0, 1, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0,
1581 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 84, 65, 78, 68,
1583 66, 89, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1584 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1585
1586 EXPECT_EQ(SRC::getProgressCode(src), 0);
1587 }
1588
1589 {
1590 // A real SRC with CC009184, but 1 byte too short
1591 std::vector<uint8_t> src{
1592 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1593 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1595 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
Matt Spinler9e1e27c2025-10-24 09:48:07 -05001596 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1597
Vijay Lobo875b6c72021-10-20 17:38:56 -05001598 EXPECT_EQ(SRC::getProgressCode(src), 0);
1599 }
1600
1601 {
1602 // A few different ones
1603 const std::map<std::string, uint32_t> progressCodes{
1604 {"12345678", 0x12345678}, {"ABCDEF00", 0xABCDEF00},
1605 {"abcdef00", 0xABCDEF00}, {"X1234567", 0},
1606 {"1234567X", 0}, {"1 ", 0}};
1607
1608 std::vector<uint8_t> src(72, 0x0);
1609
1610 for (const auto& [code, expected] : progressCodes)
1611 {
1612 setAsciiString(src, code);
1613 EXPECT_EQ(SRC::getProgressCode(src), expected);
1614 }
1615
1616 // empty
1617 src.clear();
1618 EXPECT_EQ(SRC::getProgressCode(src), 0);
1619 }
1620}
1621
1622// Test progress is in right SRC hex data field
1623TEST_F(SRCTest, TestProgressCodeField)
1624{
1625 message::Entry entry;
1626 entry.src.type = 0xBD;
1627 entry.src.reasonCode = 0xABCD;
1628 entry.subsystem = 0x42;
1629
1630 AdditionalData ad;
1631 NiceMock<MockDataInterface> dataIface;
Vijay Lobo875b6c72021-10-20 17:38:56 -05001632 EXPECT_CALL(dataIface, getRawProgressSRC())
1633 .WillOnce(Return(std::vector<uint8_t>{
1634 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1635 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1637 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1638 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}));
1639
1640 SRC src{entry, ad, dataIface};
1641 EXPECT_TRUE(src.valid());
1642
1643 // Verify that the hex vlue is set at the right hexword
1644 EXPECT_EQ(src.hexwordData()[2], 0xCC009184);
1645}