blob: 44c0f61c133ef22e2e0f81f1cd979d7a9fda5004 [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;
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800193 entry.src.hexwordADFields = {
194 {5, {"TEST1", "DESCR1"}}, // Not a user defined word
195 {6, {"TEST1", "DESCR1"}},
196 {7, {"TEST2", "DESCR2"}},
197 {8, {"TEST3", "DESCR3"}},
198 {9, {"TEST4", "DESCR4"}}};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500199
200 // Values for the SRC words pointed to above
Patrick Williamse5940632024-11-22 20:47:58 -0500201 std::map<std::string, std::string> adData{
202 {"TEST1", "0x12345678"},
203 {"TEST2", "12345678"},
204 {"TEST3", "0XDEF"},
205 {"TEST4", "Z"}};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500206 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600207 NiceMock<MockDataInterface> dataIface;
208
209 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
210
211 SRC src{entry, ad, dataIface};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500212
213 EXPECT_TRUE(src.valid());
Mike Cappsa2d7b772022-03-07 15:47:48 -0500214 EXPECT_FALSE(src.isPowerFaultEvent());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500215 EXPECT_EQ(src.size(), baseSRCSize);
216
217 const auto& hexwords = src.hexwordData();
218
219 // The spec always refers to SRC words 2 - 9, and as the hexwordData()
220 // array index starts at 0 use the math in the [] below to make it easier
221 // to tell what is being accessed.
222 EXPECT_EQ(hexwords[2 - 2] & 0xF0000000, 0); // Partition dump status
223 EXPECT_EQ(hexwords[2 - 2] & 0x00F00000, 0); // Partition boot type
224 EXPECT_EQ(hexwords[2 - 2] & 0x000000FF, 0x55); // SRC format
225 EXPECT_EQ(hexwords[3 - 2] & 0x000000FF, 0x10); // BMC position
Matt Spinler075e5ba2020-02-21 15:46:00 -0600226 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0xABCD0000); // Motherboard CCIN
Matt Spinlerbd716f02019-10-15 10:54:11 -0500227
228 // Validate more fields here as the code starts filling them in.
229
230 // Ensure hex word 5 wasn't allowed to be set to TEST1's contents
Matt Spinler3fe93e92023-04-14 14:06:59 -0500231 // And that none of the error status flags are set
Matt Spinlerbd716f02019-10-15 10:54:11 -0500232 EXPECT_EQ(hexwords[5 - 2], 0);
233
234 // The user defined hex word fields specifed in the additional data.
235 EXPECT_EQ(hexwords[6 - 2], 0x12345678); // TEST1
236 EXPECT_EQ(hexwords[7 - 2], 12345678); // TEST2
237 EXPECT_EQ(hexwords[8 - 2], 0xdef); // TEST3
238 EXPECT_EQ(hexwords[9 - 2], 0); // TEST4, but can't convert a 'Z'
239
240 EXPECT_EQ(src.asciiString(), "BD42ABCD ");
241
242 // No callouts
243 EXPECT_FALSE(src.callouts());
244
245 // May as well spot check the flatten/unflatten
246 std::vector<uint8_t> data;
247 Stream stream{data};
248 src.flatten(stream);
249
250 stream.offset(0);
251 SRC newSRC{stream};
252
253 EXPECT_TRUE(newSRC.valid());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500254 EXPECT_EQ(newSRC.asciiString(), src.asciiString());
255 EXPECT_FALSE(newSRC.callouts());
256}
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800257
Matt Spinler075e5ba2020-02-21 15:46:00 -0600258// Test when the CCIN string isn't a 4 character number
259TEST_F(SRCTest, BadCCINTest)
260{
261 message::Entry entry;
262 entry.src.type = 0xBD;
263 entry.src.reasonCode = 0xABCD;
264 entry.subsystem = 0x42;
Matt Spinler075e5ba2020-02-21 15:46:00 -0600265
Patrick Williamse5940632024-11-22 20:47:58 -0500266 std::map<std::string, std::string> adData{};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600267 AdditionalData ad{adData};
268 NiceMock<MockDataInterface> dataIface;
269
270 // First it isn't a number, then it is too long,
271 // then it is empty.
272 EXPECT_CALL(dataIface, getMotherboardCCIN)
273 .WillOnce(Return("X"))
274 .WillOnce(Return("12345"))
275 .WillOnce(Return(""));
276
277 // The CCIN in the first half should still be 0 each time.
278 {
279 SRC src{entry, ad, dataIface};
280 EXPECT_TRUE(src.valid());
281 const auto& hexwords = src.hexwordData();
282 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
283 }
284
285 {
286 SRC src{entry, ad, dataIface};
287 EXPECT_TRUE(src.valid());
288 const auto& hexwords = src.hexwordData();
289 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
290 }
291
292 {
293 SRC src{entry, ad, dataIface};
294 EXPECT_TRUE(src.valid());
295 const auto& hexwords = src.hexwordData();
296 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
297 }
298}
299
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800300// Test the getErrorDetails function
301TEST_F(SRCTest, MessageSubstitutionTest)
302{
303 auto path = SRCTest::writeData(testRegistry);
304 message::Registry registry{path};
305 auto entry = registry.lookup("0xABCD", message::LookupType::reasonCode);
306
Patrick Williamse5940632024-11-22 20:47:58 -0500307 std::map<std::string, std::string> adData{
308 {"COMPID", "0x1"},
309 {"FREQUENCY", "0x4"},
310 {"DURATION", "30"},
311 {"ERRORCODE", "0x01ABCDEF"}};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800312 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600313 NiceMock<MockDataInterface> dataIface;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800314
Matt Spinler075e5ba2020-02-21 15:46:00 -0600315 SRC src{*entry, ad, dataIface};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800316 EXPECT_TRUE(src.valid());
317
318 auto errorDetails = src.getErrorDetails(registry, DetailLevel::message);
319 ASSERT_TRUE(errorDetails);
Zane Shelley39936e32021-11-13 16:19:34 -0600320 EXPECT_EQ(errorDetails.value(),
321 "Comp 0x00000001 failed 0x00000004 times over 0x0000001E secs "
322 "with ErrorCode 0x01ABCDEF");
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800323}
Matt Spinlered046852020-03-13 13:58:15 -0500324// Test that an inventory path callout string is
325// converted into the appropriate FRU callout.
326TEST_F(SRCTest, InventoryCalloutTest)
327{
328 message::Entry entry;
329 entry.src.type = 0xBD;
330 entry.src.reasonCode = 0xABCD;
331 entry.subsystem = 0x42;
Matt Spinlered046852020-03-13 13:58:15 -0500332
Patrick Williamse5940632024-11-22 20:47:58 -0500333 std::map<std::string, std::string> adData{
334 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinlered046852020-03-13 13:58:15 -0500335 AdditionalData ad{adData};
336 NiceMock<MockDataInterface> dataIface;
337
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500338 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
339 .WillOnce(Return("UTMS-P1"));
340
341 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500342 .Times(1)
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500343 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
344 SetArgReferee<3>("123456789ABC")));
Matt Spinlered046852020-03-13 13:58:15 -0500345
346 SRC src{entry, ad, dataIface};
347 EXPECT_TRUE(src.valid());
348
349 ASSERT_TRUE(src.callouts());
350
351 EXPECT_EQ(src.callouts()->callouts().size(), 1);
352
353 auto& callout = src.callouts()->callouts().front();
354
355 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
Matt Spinler717de422020-06-04 13:10:14 -0500356 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500357
358 auto& fru = callout->fruIdentity();
359
360 EXPECT_EQ(fru->getPN().value(), "1234567");
361 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
362 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
363
364 // flatten and unflatten
365 std::vector<uint8_t> data;
366 Stream stream{data};
367 src.flatten(stream);
368
369 stream.offset(0);
370 SRC newSRC{stream};
371 EXPECT_TRUE(newSRC.valid());
372 ASSERT_TRUE(src.callouts());
373 EXPECT_EQ(src.callouts()->callouts().size(), 1);
374}
375
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500376// Test that when the location code can't be obtained that
Matt Spinler479b6922021-08-17 16:34:59 -0500377// no callout is added.
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500378TEST_F(SRCTest, InventoryCalloutNoLocCodeTest)
379{
380 message::Entry entry;
381 entry.src.type = 0xBD;
382 entry.src.reasonCode = 0xABCD;
383 entry.subsystem = 0x42;
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500384
Patrick Williamse5940632024-11-22 20:47:58 -0500385 std::map<std::string, std::string> adData{
386 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500387 AdditionalData ad{adData};
388 NiceMock<MockDataInterface> dataIface;
389
390 auto func = []() {
391 throw sdbusplus::exception::SdBusError(5, "Error");
392 return std::string{};
393 };
394
395 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
396 .Times(1)
397 .WillOnce(InvokeWithoutArgs(func));
398
399 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
400
401 SRC src{entry, ad, dataIface};
402 EXPECT_TRUE(src.valid());
403
Matt Spinler479b6922021-08-17 16:34:59 -0500404 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500405
406 // flatten and unflatten
407 std::vector<uint8_t> data;
408 Stream stream{data};
409 src.flatten(stream);
410
411 stream.offset(0);
412 SRC newSRC{stream};
413 EXPECT_TRUE(newSRC.valid());
Matt Spinler479b6922021-08-17 16:34:59 -0500414 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500415}
416
417// Test that when the VPD can't be obtained that
418// a callout is still created.
Matt Spinlered046852020-03-13 13:58:15 -0500419TEST_F(SRCTest, InventoryCalloutNoVPDTest)
420{
421 message::Entry entry;
422 entry.src.type = 0xBD;
423 entry.src.reasonCode = 0xABCD;
424 entry.subsystem = 0x42;
Matt Spinlered046852020-03-13 13:58:15 -0500425
Patrick Williamse5940632024-11-22 20:47:58 -0500426 std::map<std::string, std::string> adData{
427 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinlered046852020-03-13 13:58:15 -0500428 AdditionalData ad{adData};
429 NiceMock<MockDataInterface> dataIface;
430
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500431 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
432 .Times(1)
433 .WillOnce(Return("UTMS-P10"));
434
Matt Spinlered046852020-03-13 13:58:15 -0500435 auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
436
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500437 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500438 .Times(1)
439 .WillOnce(InvokeWithoutArgs(func));
440
441 SRC src{entry, ad, dataIface};
442 EXPECT_TRUE(src.valid());
Matt Spinlered046852020-03-13 13:58:15 -0500443 ASSERT_TRUE(src.callouts());
Matt Spinlered046852020-03-13 13:58:15 -0500444 EXPECT_EQ(src.callouts()->callouts().size(), 1);
445
446 auto& callout = src.callouts()->callouts().front();
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500447 EXPECT_EQ(callout->locationCode(), "UTMS-P10");
Matt Spinler717de422020-06-04 13:10:14 -0500448 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500449
450 auto& fru = callout->fruIdentity();
451
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500452 EXPECT_EQ(fru->getPN(), "");
453 EXPECT_EQ(fru->getCCIN(), "");
454 EXPECT_EQ(fru->getSN(), "");
455 EXPECT_FALSE(fru->getMaintProc());
456
Matt Spinlered046852020-03-13 13:58:15 -0500457 // flatten and unflatten
458 std::vector<uint8_t> data;
459 Stream stream{data};
460 src.flatten(stream);
461
462 stream.offset(0);
463 SRC newSRC{stream};
464 EXPECT_TRUE(newSRC.valid());
465 ASSERT_TRUE(src.callouts());
466 EXPECT_EQ(src.callouts()->callouts().size(), 1);
467}
Matt Spinler03984582020-04-09 13:17:58 -0500468
469TEST_F(SRCTest, RegistryCalloutTest)
470{
471 message::Entry entry;
472 entry.src.type = 0xBD;
473 entry.src.reasonCode = 0xABCD;
Matt Spinler3fe93e92023-04-14 14:06:59 -0500474 entry.src.deconfigFlag = true;
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500475 entry.src.checkstopFlag = true;
Matt Spinler03984582020-04-09 13:17:58 -0500476 entry.subsystem = 0x42;
Matt Spinler03984582020-04-09 13:17:58 -0500477
478 entry.callouts = R"(
479 [
480 {
481 "System": "systemA",
482 "CalloutList":
483 [
484 {
485 "Priority": "high",
486 "SymbolicFRU": "service_docs"
487 },
488 {
489 "Priority": "medium",
Matt Spinler2edce4e2024-01-17 11:13:51 -0600490 "Procedure": "BMC0001"
Matt Spinler03984582020-04-09 13:17:58 -0500491 }
492 ]
493 },
494 {
495 "System": "systemB",
496 "CalloutList":
497 [
498 {
499 "Priority": "high",
500 "LocCode": "P0-C8",
501 "SymbolicFRUTrusted": "service_docs"
502 },
503 {
504 "Priority": "medium",
505 "SymbolicFRUTrusted": "service_docs"
506 }
507 ]
Matt Spinleraf191c72020-06-04 11:35:13 -0500508 },
509 {
510 "System": "systemC",
511 "CalloutList":
512 [
513 {
514 "Priority": "high",
515 "LocCode": "P0-C8"
516 },
517 {
518 "Priority": "medium",
519 "LocCode": "P0-C9"
520 }
521 ]
Matt Spinler03984582020-04-09 13:17:58 -0500522 }
523 ])"_json;
524
525 {
526 // Call out a symbolic FRU and a procedure
527 AdditionalData ad;
528 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500529 std::vector<std::string> names{"systemA"};
530
Matt Spinler1ab66962020-10-29 13:21:44 -0500531 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500532
533 SRC src{entry, ad, dataIface};
534
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500535 EXPECT_TRUE(
536 src.getErrorStatusFlag(SRC::ErrorStatusFlags::deconfigured));
537 EXPECT_TRUE(src.getErrorStatusFlag(SRC::ErrorStatusFlags::hwCheckstop));
538
Matt Spinler3fe93e92023-04-14 14:06:59 -0500539 const auto& hexwords = src.hexwordData();
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500540 auto mask = static_cast<uint32_t>(SRC::ErrorStatusFlags::deconfigured) |
541 static_cast<uint32_t>(SRC::ErrorStatusFlags::hwCheckstop);
Matt Spinler3fe93e92023-04-14 14:06:59 -0500542 EXPECT_EQ(hexwords[5 - 2] & mask, mask);
543
Matt Spinler03984582020-04-09 13:17:58 -0500544 auto& callouts = src.callouts()->callouts();
545 ASSERT_EQ(callouts.size(), 2);
546
547 EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
548 EXPECT_EQ(callouts[0]->priority(), 'H');
549
550 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
551 EXPECT_EQ(callouts[1]->priority(), 'M');
552
553 auto& fru1 = callouts[0]->fruIdentity();
554 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
555 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
556 EXPECT_FALSE(fru1->getMaintProc());
557 EXPECT_FALSE(fru1->getSN());
558 EXPECT_FALSE(fru1->getCCIN());
559
560 auto& fru2 = callouts[1]->fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500561 EXPECT_EQ(fru2->getMaintProc().value(), "BMC0001");
Matt Spinler03984582020-04-09 13:17:58 -0500562 EXPECT_EQ(fru2->failingComponentType(),
563 src::FRUIdentity::maintenanceProc);
564 EXPECT_FALSE(fru2->getPN());
565 EXPECT_FALSE(fru2->getSN());
566 EXPECT_FALSE(fru2->getCCIN());
567 }
568
569 {
570 // Call out a trusted symbolic FRU with a location code, and
571 // another one without.
572 AdditionalData ad;
573 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500574 std::vector<std::string> names{"systemB"};
575
Matt Spinleraf191c72020-06-04 11:35:13 -0500576 EXPECT_CALL(dataIface, expandLocationCode).WillOnce(Return("P0-C8"));
Matt Spinler1ab66962020-10-29 13:21:44 -0500577 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500578
579 SRC src{entry, ad, dataIface};
580
581 auto& callouts = src.callouts()->callouts();
582 EXPECT_EQ(callouts.size(), 2);
583
584 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
585 EXPECT_EQ(callouts[0]->priority(), 'H');
586
587 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
588 EXPECT_EQ(callouts[1]->priority(), 'M');
589
590 auto& fru1 = callouts[0]->fruIdentity();
591 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
592 EXPECT_EQ(fru1->failingComponentType(),
593 src::FRUIdentity::symbolicFRUTrustedLocCode);
594 EXPECT_FALSE(fru1->getMaintProc());
595 EXPECT_FALSE(fru1->getSN());
596 EXPECT_FALSE(fru1->getCCIN());
597
598 // It asked for a trusted symbolic FRU, but no location code
599 // was provided so it is switched back to a normal one
600 auto& fru2 = callouts[1]->fruIdentity();
601 EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
602 EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
603 EXPECT_FALSE(fru2->getMaintProc());
604 EXPECT_FALSE(fru2->getSN());
605 EXPECT_FALSE(fru2->getCCIN());
606 }
Matt Spinleraf191c72020-06-04 11:35:13 -0500607
608 {
609 // Two hardware callouts
610 AdditionalData ad;
611 NiceMock<MockDataInterface> dataIface;
612 std::vector<std::string> names{"systemC"};
613
Matt Spinler1ab66962020-10-29 13:21:44 -0500614 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinleraf191c72020-06-04 11:35:13 -0500615
616 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
617 .WillOnce(Return("UXXX-P0-C8"));
618
619 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
620 .WillOnce(Return("UXXX-P0-C9"));
621
Matt Spinler2f9225a2020-08-05 12:58:49 -0500622 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C8", 0, false))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600623 .WillOnce(Return(std::vector<std::string>{
624 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
Matt Spinleraf191c72020-06-04 11:35:13 -0500625
Matt Spinler2f9225a2020-08-05 12:58:49 -0500626 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600627 .WillOnce(Return(std::vector<std::string>{
628 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"}));
Matt Spinleraf191c72020-06-04 11:35:13 -0500629
630 EXPECT_CALL(
631 dataIface,
632 getHWCalloutFields(
633 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _,
634 _))
635 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -0400636 .WillOnce(
637 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
638 SetArgReferee<3>("123456789ABC")));
Matt Spinleraf191c72020-06-04 11:35:13 -0500639
640 EXPECT_CALL(
641 dataIface,
642 getHWCalloutFields(
643 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1", _, _,
644 _))
645 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -0400646 .WillOnce(
647 DoAll(SetArgReferee<1>("2345678"), SetArgReferee<2>("DDDD"),
648 SetArgReferee<3>("23456789ABCD")));
Matt Spinleraf191c72020-06-04 11:35:13 -0500649
650 SRC src{entry, ad, dataIface};
651
652 auto& callouts = src.callouts()->callouts();
653 EXPECT_EQ(callouts.size(), 2);
654
655 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C8");
656 EXPECT_EQ(callouts[0]->priority(), 'H');
657
658 auto& fru1 = callouts[0]->fruIdentity();
659 EXPECT_EQ(fru1->getPN().value(), "1234567");
660 EXPECT_EQ(fru1->getCCIN().value(), "CCCC");
661 EXPECT_EQ(fru1->getSN().value(), "123456789ABC");
662
663 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C9");
664 EXPECT_EQ(callouts[1]->priority(), 'M');
665
666 auto& fru2 = callouts[1]->fruIdentity();
667 EXPECT_EQ(fru2->getPN().value(), "2345678");
668 EXPECT_EQ(fru2->getCCIN().value(), "DDDD");
669 EXPECT_EQ(fru2->getSN().value(), "23456789ABCD");
670 }
Matt Spinler03984582020-04-09 13:17:58 -0500671}
Matt Spinler717de422020-06-04 13:10:14 -0500672
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500673// Test that a symbolic FRU with a trusted location code callout
674// from the registry can get its location from the
675// CALLOUT_INVENTORY_PATH AdditionalData entry.
676TEST_F(SRCTest, SymbolicFRUWithInvPathTest)
677{
678 message::Entry entry;
679 entry.src.type = 0xBD;
680 entry.src.reasonCode = 0xABCD;
681 entry.subsystem = 0x42;
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500682
683 entry.callouts = R"(
684 [{
685 "CalloutList":
686 [
687 {
688 "Priority": "high",
689 "SymbolicFRUTrusted": "service_docs",
690 "UseInventoryLocCode": true
691 },
692 {
693 "Priority": "medium",
694 "LocCode": "P0-C8",
695 "SymbolicFRUTrusted": "pwrsply"
696 }
697 ]
698 }])"_json;
699
700 {
701 // The location code for the first symbolic FRU callout will
702 // come from this inventory path since UseInventoryLocCode is set.
703 // In this case there will be no normal FRU callout for the motherboard.
Patrick Williamse5940632024-11-22 20:47:58 -0500704 std::map<std::string, std::string> adData{
705 {"CALLOUT_INVENTORY_PATH", "motherboard"}};
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500706 AdditionalData ad{adData};
707 NiceMock<MockDataInterface> dataIface;
708 std::vector<std::string> names{"systemA"};
709
Matt Spinler1ab66962020-10-29 13:21:44 -0500710 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500711
712 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
713 .Times(1)
714 .WillOnce(Return("Ufcs-P10"));
715
716 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
717 .WillOnce(Return("Ufcs-P0-C8"));
718
719 SRC src{entry, ad, dataIface};
720
721 auto& callouts = src.callouts()->callouts();
722 EXPECT_EQ(callouts.size(), 2);
723
724 // The location code for the first symbolic FRU callout with a
725 // trusted location code comes from the motherboard.
726 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P10");
727 EXPECT_EQ(callouts[0]->priority(), 'H');
728 auto& fru1 = callouts[0]->fruIdentity();
729 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
730 EXPECT_EQ(fru1->failingComponentType(),
731 src::FRUIdentity::symbolicFRUTrustedLocCode);
732
733 // The second trusted symbolic FRU callouts uses the location
734 // code in the registry as usual.
735 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P0-C8");
736 EXPECT_EQ(callouts[1]->priority(), 'M');
737 auto& fru2 = callouts[1]->fruIdentity();
738 EXPECT_EQ(fru2->getPN().value(), "PWRSPLY");
739 EXPECT_EQ(fru2->failingComponentType(),
740 src::FRUIdentity::symbolicFRUTrustedLocCode);
741 }
742
743 {
744 // This time say we want to use the location code from
745 // the inventory, but don't pass it in and the callout should
746 // end up a regular symbolic FRU
747 entry.callouts = R"(
748 [{
749 "CalloutList":
750 [
751 {
752 "Priority": "high",
753 "SymbolicFRUTrusted": "service_docs",
754 "UseInventoryLocCode": true
755 }
756 ]
757 }])"_json;
758
759 AdditionalData ad;
760 NiceMock<MockDataInterface> dataIface;
761 std::vector<std::string> names{"systemA"};
762
Matt Spinler1ab66962020-10-29 13:21:44 -0500763 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500764
765 SRC src{entry, ad, dataIface};
766
767 auto& callouts = src.callouts()->callouts();
768 EXPECT_EQ(callouts.size(), 1);
769
770 EXPECT_EQ(callouts[0]->locationCode(), "");
771 EXPECT_EQ(callouts[0]->priority(), 'H');
772 auto& fru1 = callouts[0]->fruIdentity();
773 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
774 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
775 }
776}
777
Matt Spinler7b923722025-03-19 13:17:23 -0500778TEST_F(SRCTest, RegistryCalloutCantGetLocTest)
779{
780 message::Entry entry;
781 entry.src.type = 0xBD;
782 entry.src.reasonCode = 0xABCD;
783 entry.src.deconfigFlag = true;
784 entry.src.checkstopFlag = true;
785 entry.subsystem = 0x42;
786
787 entry.callouts = R"(
788 [{
789 "CalloutList":
790 [
791 {
792 "Priority": "high",
793 "LocCode": "P0-C8"
794 },
795 {
796 "Priority": "medium",
797 "LocCode": "P0-C9"
798 }
799 ]
800 }])"_json;
801
802 {
803 // The calls to expand the location codes will fail, but it should
804 // still create the callouts with the unexpanded values and no HW
805 // fields.
806 AdditionalData ad;
807 NiceMock<MockDataInterface> dataIface;
808 std::vector<std::string> names{"systemC"};
809
810 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
811
812 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
813 .WillRepeatedly(Throw(std::runtime_error("Fail")));
814
815 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
816 .WillRepeatedly(Throw(std::runtime_error("Fail")));
817
818 EXPECT_CALL(dataIface, getInventoryFromLocCode(_, _, _)).Times(0);
819
820 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
821
822 SRC src{entry, ad, dataIface};
823
824 auto& callouts = src.callouts()->callouts();
825 ASSERT_EQ(callouts.size(), 2);
826
827 // Only unexpanded location codes
828 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
829 EXPECT_EQ(callouts[0]->priority(), 'H');
830
831 auto& fru1 = callouts[0]->fruIdentity();
832 EXPECT_EQ(fru1->getPN().value(), "");
833 EXPECT_EQ(fru1->getCCIN().value(), "");
834 EXPECT_EQ(fru1->getSN().value(), "");
835
836 EXPECT_EQ(callouts[1]->locationCode(), "P0-C9");
837 EXPECT_EQ(callouts[1]->priority(), 'M');
838
839 auto& fru2 = callouts[1]->fruIdentity();
840 EXPECT_EQ(fru2->getPN().value(), "");
841 EXPECT_EQ(fru2->getCCIN().value(), "");
842 EXPECT_EQ(fru2->getSN().value(), "");
843 }
844}
845
846TEST_F(SRCTest, TrustedSymbolicFRUCantGetLocTest)
847{
848 message::Entry entry;
849 entry.src.type = 0xBD;
850 entry.src.reasonCode = 0xABCD;
851 entry.subsystem = 0x42;
852
853 entry.callouts = R"(
854 [{
855 "CalloutList":
856 [
857 {
858 "Priority": "medium",
859 "LocCode": "P0-C8",
860 "SymbolicFRUTrusted": "pwrsply"
861 }
862 ]
863 }])"_json;
864
865 std::map<std::string, std::string> adData;
866 AdditionalData ad{adData};
867 NiceMock<MockDataInterface> dataIface;
868 std::vector<std::string> names{"systemA"};
869
870 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
871
872 // The call to expand the location code will fail, but it should
873 // still create the callout with the unexpanded value and the
874 // symbolic FRU can't be trusted.
875 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
876 .WillRepeatedly(Throw(std::runtime_error("Fail")));
877
878 SRC src{entry, ad, dataIface};
879
880 auto& callouts = src.callouts()->callouts();
881 ASSERT_EQ(callouts.size(), 1);
882
883 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
884 EXPECT_EQ(callouts[0]->priority(), 'M');
885 auto& fru = callouts[0]->fruIdentity();
886 EXPECT_EQ(fru->getPN().value(), "PWRSPLY");
887 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
888}
889
Matt Spinler717de422020-06-04 13:10:14 -0500890// Test looking up device path fails in the callout jSON.
891TEST_F(SRCTest, DevicePathCalloutTest)
892{
893 message::Entry entry;
894 entry.src.type = 0xBD;
895 entry.src.reasonCode = 0xABCD;
896 entry.subsystem = 0x42;
Matt Spinler717de422020-06-04 13:10:14 -0500897
898 const auto calloutJSON = R"(
899 {
900 "I2C":
901 {
902 "14":
903 {
904 "114":
905 {
906 "Callouts":[
907 {
908 "Name": "/chassis/motherboard/cpu0",
909 "LocationCode": "P1-C40",
910 "Priority": "H"
911 },
912 {
913 "Name": "/chassis/motherboard",
914 "LocationCode": "P1",
915 "Priority": "M"
916 },
917 {
918 "Name": "/chassis/motherboard/bmc",
919 "LocationCode": "P1-C15",
920 "Priority": "L"
921 }
922 ],
923 "Dest": "proc 0 target"
924 }
925 }
926 }
927 })";
928
929 auto dataPath = getPELReadOnlyDataPath();
930 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
931 file << calloutJSON;
932 file.close();
933
934 NiceMock<MockDataInterface> dataIface;
935 std::vector<std::string> names{"systemA"};
936
937 EXPECT_CALL(dataIface, getSystemNames)
938 .Times(5)
Matt Spinler1ab66962020-10-29 13:21:44 -0500939 .WillRepeatedly(Return(names));
Matt Spinler717de422020-06-04 13:10:14 -0500940
Matt Spinler2f9225a2020-08-05 12:58:49 -0500941 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500942 .Times(3)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600943 .WillRepeatedly(Return(std::vector<std::string>{
944 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
Matt Spinler717de422020-06-04 13:10:14 -0500945
Matt Spinler2f9225a2020-08-05 12:58:49 -0500946 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500947 .Times(3)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600948 .WillRepeatedly(Return(std::vector<std::string>{
949 "/xyz/openbmc_project/inventory/chassis/motherboard"}));
Matt Spinler717de422020-06-04 13:10:14 -0500950
Matt Spinler2f9225a2020-08-05 12:58:49 -0500951 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C15", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500952 .Times(3)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600953 .WillRepeatedly(Return(std::vector<std::string>{
954 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc"}));
Matt Spinler717de422020-06-04 13:10:14 -0500955
Matt Spinler0d92b522021-06-16 13:28:17 -0600956 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500957 .Times(3)
958 .WillRepeatedly(Return("Ufcs-P1-C40"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600959
960 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500961 .Times(3)
962 .WillRepeatedly(Return("Ufcs-P1"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600963
964 EXPECT_CALL(dataIface, expandLocationCode("P1-C15", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500965 .Times(3)
966 .WillRepeatedly(Return("Ufcs-P1-C15"));
967
Patrick Williams075c7922024-08-16 15:19:49 -0400968 EXPECT_CALL(dataIface,
969 getHWCalloutFields(
970 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0",
971 _, _, _))
Matt Spinler717de422020-06-04 13:10:14 -0500972 .Times(3)
Patrick Williams075c7922024-08-16 15:19:49 -0400973 .WillRepeatedly(
974 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
975 SetArgReferee<3>("123456789ABC")));
Matt Spinler717de422020-06-04 13:10:14 -0500976 EXPECT_CALL(
977 dataIface,
978 getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
979 _, _, _))
980 .Times(3)
Patrick Williams075c7922024-08-16 15:19:49 -0400981 .WillRepeatedly(
982 DoAll(SetArgReferee<1>("7654321"), SetArgReferee<2>("MMMM"),
983 SetArgReferee<3>("CBA987654321")));
984 EXPECT_CALL(dataIface,
985 getHWCalloutFields(
986 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _,
987 _, _))
Matt Spinler717de422020-06-04 13:10:14 -0500988 .Times(3)
Patrick Williams075c7922024-08-16 15:19:49 -0400989 .WillRepeatedly(
990 DoAll(SetArgReferee<1>("7123456"), SetArgReferee<2>("BBBB"),
991 SetArgReferee<3>("C123456789AB")));
Matt Spinler717de422020-06-04 13:10:14 -0500992
993 // Call this below with different AdditionalData values that
994 // result in the same callouts.
995 auto checkCallouts = [&entry, &dataIface](const auto& items) {
996 AdditionalData ad{items};
997 SRC src{entry, ad, dataIface};
998
999 ASSERT_TRUE(src.callouts());
1000 auto& callouts = src.callouts()->callouts();
1001
1002 ASSERT_EQ(callouts.size(), 3);
1003
1004 {
1005 EXPECT_EQ(callouts[0]->priority(), 'H');
1006 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
1007
1008 auto& fru = callouts[0]->fruIdentity();
1009 EXPECT_EQ(fru->getPN().value(), "1234567");
1010 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1011 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1012 }
1013 {
1014 EXPECT_EQ(callouts[1]->priority(), 'M');
1015 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
1016
1017 auto& fru = callouts[1]->fruIdentity();
1018 EXPECT_EQ(fru->getPN().value(), "7654321");
1019 EXPECT_EQ(fru->getCCIN().value(), "MMMM");
1020 EXPECT_EQ(fru->getSN().value(), "CBA987654321");
1021 }
1022 {
1023 EXPECT_EQ(callouts[2]->priority(), 'L');
1024 EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
1025
1026 auto& fru = callouts[2]->fruIdentity();
1027 EXPECT_EQ(fru->getPN().value(), "7123456");
1028 EXPECT_EQ(fru->getCCIN().value(), "BBBB");
1029 EXPECT_EQ(fru->getSN().value(), "C123456789AB");
1030 }
1031 };
1032
1033 {
1034 // Callouts based on the device path
Patrick Williamse5940632024-11-22 20:47:58 -05001035 std::map<std::string, std::string> items{
1036 {"CALLOUT_ERRNO", "5"},
1037 {"CALLOUT_DEVICE_PATH",
1038 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
Matt Spinler717de422020-06-04 13:10:14 -05001039
1040 checkCallouts(items);
1041 }
1042
1043 {
1044 // Callouts based on the I2C bus and address
Patrick Williamse5940632024-11-22 20:47:58 -05001045 std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1046 {"CALLOUT_IIC_BUS", "14"},
1047 {"CALLOUT_IIC_ADDR", "0x72"}};
Matt Spinler717de422020-06-04 13:10:14 -05001048 checkCallouts(items);
1049 }
1050
1051 {
1052 // Also based on I2C bus and address, but with bus = /dev/i2c-14
Patrick Williamse5940632024-11-22 20:47:58 -05001053 std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1054 {"CALLOUT_IIC_BUS", "14"},
1055 {"CALLOUT_IIC_ADDR", "0x72"}};
Matt Spinler717de422020-06-04 13:10:14 -05001056 checkCallouts(items);
1057 }
1058
1059 {
1060 // Callout not found
Patrick Williamse5940632024-11-22 20:47:58 -05001061 std::map<std::string, std::string> items{
1062 {"CALLOUT_ERRNO", "5"},
1063 {"CALLOUT_DEVICE_PATH",
1064 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"}};
Matt Spinler717de422020-06-04 13:10:14 -05001065
1066 AdditionalData ad{items};
1067 SRC src{entry, ad, dataIface};
1068
1069 EXPECT_FALSE(src.callouts());
1070 ASSERT_EQ(src.getDebugData().size(), 1);
1071 EXPECT_EQ(src.getDebugData()[0],
1072 "Problem looking up I2C callouts on 24 18: "
1073 "[json.exception.out_of_range.403] key '24' not found");
1074 }
1075
1076 {
1077 // Callout not found
Patrick Williamse5940632024-11-22 20:47:58 -05001078 std::map<std::string, std::string> items{{"CALLOUT_ERRNO", "5"},
1079 {"CALLOUT_IIC_BUS", "22"},
1080 {"CALLOUT_IIC_ADDR", "0x99"}};
Matt Spinler717de422020-06-04 13:10:14 -05001081 AdditionalData ad{items};
1082 SRC src{entry, ad, dataIface};
1083
1084 EXPECT_FALSE(src.callouts());
1085 ASSERT_EQ(src.getDebugData().size(), 1);
1086 EXPECT_EQ(src.getDebugData()[0],
1087 "Problem looking up I2C callouts on 22 153: "
1088 "[json.exception.out_of_range.403] key '22' not found");
1089 }
Matt Spinler7b923722025-03-19 13:17:23 -05001090}
1091
1092TEST_F(SRCTest, DevicePathCantGetLocTest)
1093{
1094 message::Entry entry;
1095 entry.src.type = 0xBD;
1096 entry.src.reasonCode = 0xABCD;
1097 entry.subsystem = 0x42;
1098
1099 const auto calloutJSON = R"(
1100 {
1101 "I2C":
1102 {
1103 "14":
1104 {
1105 "114":
1106 {
1107 "Callouts":[
1108 {
1109 "Name": "/chassis/motherboard/cpu0",
1110 "LocationCode": "P1-C40",
1111 "Priority": "H"
1112 },
1113 {
1114 "Name": "/chassis/motherboard",
1115 "LocationCode": "P1",
1116 "Priority": "M"
1117 }
1118 ],
1119 "Dest": "proc 0 target"
1120 }
1121 }
1122 }
1123 })";
1124
1125 auto dataPath = getPELReadOnlyDataPath();
1126 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
1127 file << calloutJSON;
1128 file.close();
1129
1130 NiceMock<MockDataInterface> dataIface;
1131 std::vector<std::string> names{"systemA"};
1132
1133 EXPECT_CALL(dataIface, getSystemNames).WillRepeatedly(Return(names));
1134
1135 // The calls to expand the location codes will fail, so still create
1136 // the callouts with the unexpanded values and no HW fields
1137
1138 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
1139 .WillRepeatedly(Throw(std::runtime_error("Fail")));
1140
1141 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
1142 .WillRepeatedly(Throw(std::runtime_error("Fail")));
1143
1144 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
1145 .Times(0);
1146 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false)).Times(0);
1147
1148 std::map<std::string, std::string> items{
1149 {"CALLOUT_ERRNO", "5"},
1150 {"CALLOUT_DEVICE_PATH",
1151 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"}};
1152
1153 AdditionalData ad{items};
1154 SRC src{entry, ad, dataIface};
1155
1156 ASSERT_TRUE(src.callouts());
1157 auto& callouts = src.callouts()->callouts();
1158
1159 ASSERT_EQ(callouts.size(), 2);
1160
1161 // Should just contain the unexpanded location codes
1162 {
1163 EXPECT_EQ(callouts[0]->priority(), 'H');
1164 EXPECT_EQ(callouts[0]->locationCode(), "P1-C40");
1165
1166 auto& fru = callouts[0]->fruIdentity();
1167 EXPECT_EQ(fru->getPN().value(), "");
1168 EXPECT_EQ(fru->getCCIN().value(), "");
1169 EXPECT_EQ(fru->getSN().value(), "");
1170 }
1171 {
1172 EXPECT_EQ(callouts[1]->priority(), 'M');
1173 EXPECT_EQ(callouts[1]->locationCode(), "P1");
1174
1175 auto& fru = callouts[1]->fruIdentity();
1176 EXPECT_EQ(fru->getPN().value(), "");
1177 EXPECT_EQ(fru->getCCIN().value(), "");
1178 EXPECT_EQ(fru->getSN().value(), "");
1179 }
Matt Spinler717de422020-06-04 13:10:14 -05001180
1181 fs::remove_all(dataPath);
1182}
Matt Spinler3bdd0112020-08-27 10:24:34 -05001183
1184// Test when callouts are passed in via JSON
1185TEST_F(SRCTest, JsonCalloutsTest)
1186{
1187 const auto jsonCallouts = R"(
1188 [
1189 {
1190 "LocationCode": "P0-C1",
1191 "Priority": "H",
1192 "MRUs": [
1193 {
1194 "ID": 42,
1195 "Priority": "H"
1196 },
1197 {
1198 "ID": 43,
1199 "Priority": "M"
1200 }
1201 ]
1202 },
1203 {
1204 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
1205 "Priority": "M",
1206 "Guarded": true,
1207 "Deconfigured": true
1208 },
1209 {
1210 "Procedure": "PROCEDU",
1211 "Priority": "A"
1212 },
1213 {
1214 "SymbolicFRU": "TRUSTED",
1215 "Priority": "B",
1216 "TrustedLocationCode": true,
1217 "LocationCode": "P1-C23"
1218 },
1219 {
1220 "SymbolicFRU": "FRUTST1",
1221 "Priority": "C",
1222 "LocationCode": "P1-C24"
1223 },
1224 {
1225 "SymbolicFRU": "FRUTST2LONG",
1226 "Priority": "L"
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001227 },
1228 {
1229 "Procedure": "fsi_path",
1230 "Priority": "L"
1231 },
1232 {
1233 "SymbolicFRU": "ambient_temp",
1234 "Priority": "L"
Matt Spinler3bdd0112020-08-27 10:24:34 -05001235 }
1236 ]
1237 )"_json;
1238
1239 message::Entry entry;
1240 entry.src.type = 0xBD;
1241 entry.src.reasonCode = 0xABCD;
1242 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001243
1244 AdditionalData ad;
1245 NiceMock<MockDataInterface> dataIface;
1246
1247 // Callout 0 mock calls
1248 {
1249 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1250 .Times(1)
1251 .WillOnce(Return("UXXX-P0-C1"));
1252 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1253 .Times(1)
Matt Spinlerbad056b2023-01-25 14:16:57 -06001254 .WillOnce(Return(std::vector<std::string>{
1255 "/inv/system/chassis/motherboard/bmc"}));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001256 EXPECT_CALL(
1257 dataIface,
1258 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1259 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -04001260 .WillOnce(
1261 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1262 SetArgReferee<3>("123456789ABC")));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001263 }
1264 // Callout 1 mock calls
1265 {
1266 EXPECT_CALL(dataIface,
1267 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1268 .WillOnce(Return("UYYY-P5"));
1269 EXPECT_CALL(
1270 dataIface,
1271 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1272 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -04001273 .WillOnce(
1274 DoAll(SetArgReferee<1>("2345678"), SetArgReferee<2>("DDDD"),
1275 SetArgReferee<3>("23456789ABCD")));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001276 }
1277 // Callout 3 mock calls
1278 {
1279 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1280 .Times(1)
1281 .WillOnce(Return("UXXX-P1-C23"));
1282 }
1283 // Callout 4 mock calls
1284 {
1285 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1286 .Times(1)
1287 .WillOnce(Return("UXXX-P1-C24"));
1288 }
1289
1290 SRC src{entry, ad, jsonCallouts, dataIface};
1291 ASSERT_TRUE(src.callouts());
1292
Matt Spinlerafa2c792020-08-27 11:01:39 -05001293 // Check the guarded and deconfigured flags
1294 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1295
Matt Spinler3bdd0112020-08-27 10:24:34 -05001296 const auto& callouts = src.callouts()->callouts();
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001297 ASSERT_EQ(callouts.size(), 8);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001298
1299 // Check callout 0
1300 {
1301 EXPECT_EQ(callouts[0]->priority(), 'H');
1302 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1303
1304 auto& fru = callouts[0]->fruIdentity();
1305 EXPECT_EQ(fru->getPN().value(), "1234567");
1306 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1307 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1308 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001309
1310 auto& mruCallouts = callouts[0]->mru();
1311 ASSERT_TRUE(mruCallouts);
1312 auto& mrus = mruCallouts->mrus();
1313 ASSERT_EQ(mrus.size(), 2);
1314 EXPECT_EQ(mrus[0].id, 42);
1315 EXPECT_EQ(mrus[0].priority, 'H');
1316 EXPECT_EQ(mrus[1].id, 43);
1317 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001318 }
1319
1320 // Check callout 1
1321 {
1322 EXPECT_EQ(callouts[1]->priority(), 'M');
1323 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1324
1325 auto& fru = callouts[1]->fruIdentity();
1326 EXPECT_EQ(fru->getPN().value(), "2345678");
1327 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1328 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1329 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1330 }
1331
1332 // Check callout 2
1333 {
1334 EXPECT_EQ(callouts[2]->priority(), 'A');
1335 EXPECT_EQ(callouts[2]->locationCode(), "");
1336
1337 auto& fru = callouts[2]->fruIdentity();
1338 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1339 EXPECT_EQ(fru->failingComponentType(),
1340 src::FRUIdentity::maintenanceProc);
1341 }
1342
1343 // Check callout 3
1344 {
1345 EXPECT_EQ(callouts[3]->priority(), 'B');
1346 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1347
1348 auto& fru = callouts[3]->fruIdentity();
1349 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1350 EXPECT_EQ(fru->failingComponentType(),
1351 src::FRUIdentity::symbolicFRUTrustedLocCode);
1352 }
1353
1354 // Check callout 4
1355 {
1356 EXPECT_EQ(callouts[4]->priority(), 'C');
1357 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1358
1359 auto& fru = callouts[4]->fruIdentity();
1360 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1361 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1362 }
1363
1364 // Check callout 5
1365 {
1366 EXPECT_EQ(callouts[5]->priority(), 'L');
1367 EXPECT_EQ(callouts[5]->locationCode(), "");
1368
1369 auto& fru = callouts[5]->fruIdentity();
1370 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1371 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1372 }
1373
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001374 // Check callout 6
1375 {
1376 EXPECT_EQ(callouts[6]->priority(), 'L');
1377 EXPECT_EQ(callouts[6]->locationCode(), "");
1378
1379 auto& fru = callouts[6]->fruIdentity();
1380 EXPECT_EQ(fru->getMaintProc().value(), "BMC0004");
1381 EXPECT_EQ(fru->failingComponentType(),
1382 src::FRUIdentity::maintenanceProc);
1383 }
1384
1385 // Check callout 7
1386 {
1387 EXPECT_EQ(callouts[7]->priority(), 'L');
1388 EXPECT_EQ(callouts[7]->locationCode(), "");
1389
1390 auto& fru = callouts[7]->fruIdentity();
1391 EXPECT_EQ(fru->getPN().value(), "AMBTEMP");
1392 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1393 }
1394
Matt Spinler3bdd0112020-08-27 10:24:34 -05001395 // Check that it didn't find any errors
1396 const auto& data = src.getDebugData();
1397 EXPECT_TRUE(data.empty());
1398}
1399
1400TEST_F(SRCTest, JsonBadCalloutsTest)
1401{
1402 // The first call will have a Throw in a mock call.
1403 // The second will have a different Throw in a mock call.
1404 // The others have issues with the Priority field.
1405 const auto jsonCallouts = R"(
1406 [
1407 {
1408 "LocationCode": "P0-C1",
1409 "Priority": "H"
1410 },
1411 {
1412 "LocationCode": "P0-C2",
1413 "Priority": "H"
1414 },
1415 {
1416 "LocationCode": "P0-C3"
1417 },
1418 {
1419 "LocationCode": "P0-C4",
1420 "Priority": "X"
1421 }
1422 ]
1423 )"_json;
1424
1425 message::Entry entry;
1426 entry.src.type = 0xBD;
1427 entry.src.reasonCode = 0xABCD;
1428 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001429
1430 AdditionalData ad;
1431 NiceMock<MockDataInterface> dataIface;
1432
1433 // Callout 0 mock calls
1434 // Expand location code will fail, so the unexpanded location
1435 // code should show up in the callout instead.
1436 {
1437 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1438 .WillOnce(Throw(std::runtime_error("Fail")));
1439
1440 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1441 .Times(1)
Matt Spinlerbad056b2023-01-25 14:16:57 -06001442 .WillOnce(Return(std::vector<std::string>{
1443 "/inv/system/chassis/motherboard/bmc"}));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001444 EXPECT_CALL(
1445 dataIface,
1446 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1447 .Times(1)
Patrick Williams075c7922024-08-16 15:19:49 -04001448 .WillOnce(
1449 DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1450 SetArgReferee<3>("123456789ABC")));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001451 }
1452
1453 // Callout 1 mock calls
Matt Spinler7b923722025-03-19 13:17:23 -05001454 // getInventoryFromLocCode will fail, so a callout with just the
1455 // location code will be created.
Matt Spinler3bdd0112020-08-27 10:24:34 -05001456 {
1457 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1458 .Times(1)
1459 .WillOnce(Return("UXXX-P0-C2"));
1460
1461 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1462 .Times(1)
1463 .WillOnce(Throw(std::runtime_error("Fail")));
1464 }
1465
1466 SRC src{entry, ad, jsonCallouts, dataIface};
1467
1468 ASSERT_TRUE(src.callouts());
1469
1470 const auto& callouts = src.callouts()->callouts();
1471
Matt Spinler7b923722025-03-19 13:17:23 -05001472 // The first callout will have the unexpanded location code.
1473 ASSERT_EQ(callouts.size(), 2);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001474
Matt Spinler7b923722025-03-19 13:17:23 -05001475 EXPECT_EQ(callouts[0]->priority(), 'H');
1476 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
Matt Spinler3bdd0112020-08-27 10:24:34 -05001477
Matt Spinler7b923722025-03-19 13:17:23 -05001478 auto& fru0 = callouts[0]->fruIdentity();
1479 EXPECT_EQ(fru0->getPN().value(), "1234567");
1480 EXPECT_EQ(fru0->getCCIN().value(), "CCCC");
1481 EXPECT_EQ(fru0->getSN().value(), "123456789ABC");
1482 EXPECT_EQ(fru0->failingComponentType(), src::FRUIdentity::hardwareFRU);
1483
1484 // The second callout will have empty HW details.
1485 EXPECT_EQ(callouts[1]->priority(), 'H');
1486 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C2");
1487
1488 auto& fru1 = callouts[1]->fruIdentity();
1489 EXPECT_EQ(fru1->getPN().value(), "");
1490 EXPECT_EQ(fru1->getCCIN().value(), "");
1491 EXPECT_EQ(fru1->getSN().value(), "");
1492 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001493
1494 const auto& data = src.getDebugData();
1495 ASSERT_EQ(data.size(), 4);
1496 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
Matt Spinler7b923722025-03-19 13:17:23 -05001497 EXPECT_STREQ(
1498 data[1].c_str(),
1499 "Unable to get inventory path from location code: P0-C2: Fail");
Matt Spinler3bdd0112020-08-27 10:24:34 -05001500 EXPECT_STREQ(data[2].c_str(),
1501 "Failed extracting callout data from JSON: "
1502 "[json.exception.out_of_range.403] key 'Priority' not found");
1503 EXPECT_STREQ(data[3].c_str(),
1504 "Failed extracting callout data from JSON: Invalid "
1505 "priority 'X' found in JSON callout");
1506}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001507
1508// Test that an inventory path callout can have
1509// a different priority than H.
1510TEST_F(SRCTest, InventoryCalloutTestPriority)
1511{
1512 message::Entry entry;
1513 entry.src.type = 0xBD;
1514 entry.src.reasonCode = 0xABCD;
1515 entry.subsystem = 0x42;
Miguel Gomez53ef1552020-10-14 21:16:32 +00001516
Patrick Williamse5940632024-11-22 20:47:58 -05001517 std::map<std::string, std::string> adData{
1518 {"CALLOUT_INVENTORY_PATH", "motherboard"}, {"CALLOUT_PRIORITY", "M"}};
Miguel Gomez53ef1552020-10-14 21:16:32 +00001519 AdditionalData ad{adData};
1520 NiceMock<MockDataInterface> dataIface;
1521
1522 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1523 .WillOnce(Return("UTMS-P1"));
1524
1525 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1526 .Times(1)
1527 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1528 SetArgReferee<3>("123456789ABC")));
1529
1530 SRC src{entry, ad, dataIface};
1531 EXPECT_TRUE(src.valid());
1532
1533 ASSERT_TRUE(src.callouts());
1534
1535 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1536
1537 auto& callout = src.callouts()->callouts().front();
1538
1539 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1540 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001541}
Sumit Kumar9d43a722021-08-24 09:46:19 -05001542
Sumit Kumar50bfa692022-01-06 06:48:26 -06001543// Test SRC with additional data - PEL_SUBSYSTEM
1544TEST_F(SRCTest, TestPELSubsystem)
1545{
1546 message::Entry entry;
1547 entry.src.type = 0xBD;
1548 entry.src.reasonCode = 0xABCD;
1549 entry.subsystem = 0x42;
Sumit Kumar50bfa692022-01-06 06:48:26 -06001550
1551 // Values for the SRC words pointed to above
Patrick Williamse5940632024-11-22 20:47:58 -05001552 std::map<std::string, std::string> adData{{"PEL_SUBSYSTEM", "0x20"}};
Sumit Kumar50bfa692022-01-06 06:48:26 -06001553 AdditionalData ad{adData};
1554 NiceMock<MockDataInterface> dataIface;
1555
1556 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
1557
Sumit Kumar50bfa692022-01-06 06:48:26 -06001558 SRC src{entry, ad, dataIface};
1559
1560 EXPECT_TRUE(src.valid());
1561
1562 EXPECT_EQ(src.asciiString(), "BD20ABCD ");
1563}
Vijay Lobo875b6c72021-10-20 17:38:56 -05001564
1565void setAsciiString(std::vector<uint8_t>& src, const std::string& value)
1566{
1567 assert(40 + value.size() <= src.size());
1568
1569 for (size_t i = 0; i < value.size(); i++)
1570 {
1571 src[40 + i] = value[i];
1572 }
1573}
1574
1575TEST_F(SRCTest, TestGetProgressCode)
1576{
1577 {
1578 // A real SRC with CC009184
1579 std::vector<uint8_t> src{
1580 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1581 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1583 49, 56, 52, 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), 0xCC009184);
1587 }
1588
1589 {
1590 // A real SRC with STANDBY
1591 std::vector<uint8_t> src{
1592 2, 0, 0, 1, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0,
1593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 84, 65, 78, 68,
1595 66, 89, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1596 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1597
1598 EXPECT_EQ(SRC::getProgressCode(src), 0);
1599 }
1600
1601 {
1602 // A real SRC with CC009184, but 1 byte too short
1603 std::vector<uint8_t> src{
1604 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1605 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1606 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1607 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1608 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1609 src.resize(71);
1610 EXPECT_EQ(SRC::getProgressCode(src), 0);
1611 }
1612
1613 {
1614 // A few different ones
1615 const std::map<std::string, uint32_t> progressCodes{
1616 {"12345678", 0x12345678}, {"ABCDEF00", 0xABCDEF00},
1617 {"abcdef00", 0xABCDEF00}, {"X1234567", 0},
1618 {"1234567X", 0}, {"1 ", 0}};
1619
1620 std::vector<uint8_t> src(72, 0x0);
1621
1622 for (const auto& [code, expected] : progressCodes)
1623 {
1624 setAsciiString(src, code);
1625 EXPECT_EQ(SRC::getProgressCode(src), expected);
1626 }
1627
1628 // empty
1629 src.clear();
1630 EXPECT_EQ(SRC::getProgressCode(src), 0);
1631 }
1632}
1633
1634// Test progress is in right SRC hex data field
1635TEST_F(SRCTest, TestProgressCodeField)
1636{
1637 message::Entry entry;
1638 entry.src.type = 0xBD;
1639 entry.src.reasonCode = 0xABCD;
1640 entry.subsystem = 0x42;
1641
1642 AdditionalData ad;
1643 NiceMock<MockDataInterface> dataIface;
Vijay Lobo875b6c72021-10-20 17:38:56 -05001644 EXPECT_CALL(dataIface, getRawProgressSRC())
1645 .WillOnce(Return(std::vector<uint8_t>{
1646 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1647 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1648 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1649 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1650 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}));
1651
1652 SRC src{entry, ad, dataIface};
1653 EXPECT_TRUE(src.valid());
1654
1655 // Verify that the hex vlue is set at the right hexword
1656 EXPECT_EQ(src.hexwordData()[2], 0xCC009184);
1657}