blob: a4c5628574a55299a2f47e7f8e8ae3827de08696 [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
201 std::vector<std::string> adData{"TEST1=0x12345678", "TEST2=12345678",
202 "TEST3=0XDEF", "TEST4=Z"};
203 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600204 NiceMock<MockDataInterface> dataIface;
205
206 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
207
Sumit Kumar9d43a722021-08-24 09:46:19 -0500208 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
209 "system/entry"};
210 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
211 .WillOnce(Return(std::vector<bool>{false, false, false}));
212
Matt Spinler075e5ba2020-02-21 15:46:00 -0600213 SRC src{entry, ad, dataIface};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500214
215 EXPECT_TRUE(src.valid());
Mike Cappsa2d7b772022-03-07 15:47:48 -0500216 EXPECT_FALSE(src.isPowerFaultEvent());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500217 EXPECT_EQ(src.size(), baseSRCSize);
218
219 const auto& hexwords = src.hexwordData();
220
221 // The spec always refers to SRC words 2 - 9, and as the hexwordData()
222 // array index starts at 0 use the math in the [] below to make it easier
223 // to tell what is being accessed.
224 EXPECT_EQ(hexwords[2 - 2] & 0xF0000000, 0); // Partition dump status
225 EXPECT_EQ(hexwords[2 - 2] & 0x00F00000, 0); // Partition boot type
226 EXPECT_EQ(hexwords[2 - 2] & 0x000000FF, 0x55); // SRC format
227 EXPECT_EQ(hexwords[3 - 2] & 0x000000FF, 0x10); // BMC position
Matt Spinler075e5ba2020-02-21 15:46:00 -0600228 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0xABCD0000); // Motherboard CCIN
Matt Spinlerbd716f02019-10-15 10:54:11 -0500229
230 // Validate more fields here as the code starts filling them in.
231
232 // Ensure hex word 5 wasn't allowed to be set to TEST1's contents
233 EXPECT_EQ(hexwords[5 - 2], 0);
234
235 // The user defined hex word fields specifed in the additional data.
236 EXPECT_EQ(hexwords[6 - 2], 0x12345678); // TEST1
237 EXPECT_EQ(hexwords[7 - 2], 12345678); // TEST2
238 EXPECT_EQ(hexwords[8 - 2], 0xdef); // TEST3
239 EXPECT_EQ(hexwords[9 - 2], 0); // TEST4, but can't convert a 'Z'
240
241 EXPECT_EQ(src.asciiString(), "BD42ABCD ");
242
243 // No callouts
244 EXPECT_FALSE(src.callouts());
245
246 // May as well spot check the flatten/unflatten
247 std::vector<uint8_t> data;
248 Stream stream{data};
249 src.flatten(stream);
250
251 stream.offset(0);
252 SRC newSRC{stream};
253
254 EXPECT_TRUE(newSRC.valid());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500255 EXPECT_EQ(newSRC.asciiString(), src.asciiString());
256 EXPECT_FALSE(newSRC.callouts());
257}
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800258
Matt Spinler075e5ba2020-02-21 15:46:00 -0600259// Test when the CCIN string isn't a 4 character number
260TEST_F(SRCTest, BadCCINTest)
261{
262 message::Entry entry;
263 entry.src.type = 0xBD;
264 entry.src.reasonCode = 0xABCD;
265 entry.subsystem = 0x42;
Matt Spinler075e5ba2020-02-21 15:46:00 -0600266
267 std::vector<std::string> adData{};
268 AdditionalData ad{adData};
269 NiceMock<MockDataInterface> dataIface;
270
Sumit Kumar9d43a722021-08-24 09:46:19 -0500271 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
272 "system/entry"};
273 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
274 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
275
Matt Spinler075e5ba2020-02-21 15:46:00 -0600276 // First it isn't a number, then it is too long,
277 // then it is empty.
278 EXPECT_CALL(dataIface, getMotherboardCCIN)
279 .WillOnce(Return("X"))
280 .WillOnce(Return("12345"))
281 .WillOnce(Return(""));
282
283 // The CCIN in the first half should still be 0 each time.
284 {
285 SRC src{entry, ad, dataIface};
286 EXPECT_TRUE(src.valid());
287 const auto& hexwords = src.hexwordData();
288 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
289 }
290
291 {
292 SRC src{entry, ad, dataIface};
293 EXPECT_TRUE(src.valid());
294 const auto& hexwords = src.hexwordData();
295 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
296 }
297
298 {
299 SRC src{entry, ad, dataIface};
300 EXPECT_TRUE(src.valid());
301 const auto& hexwords = src.hexwordData();
302 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
303 }
304}
305
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800306// Test the getErrorDetails function
307TEST_F(SRCTest, MessageSubstitutionTest)
308{
309 auto path = SRCTest::writeData(testRegistry);
310 message::Registry registry{path};
311 auto entry = registry.lookup("0xABCD", message::LookupType::reasonCode);
312
313 std::vector<std::string> adData{"COMPID=0x1", "FREQUENCY=0x4",
314 "DURATION=30", "ERRORCODE=0x01ABCDEF"};
315 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600316 NiceMock<MockDataInterface> dataIface;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800317
Sumit Kumar9d43a722021-08-24 09:46:19 -0500318 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
319 "system/entry"};
320 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
321 .WillOnce(Return(std::vector<bool>{false, false, false}));
322
Matt Spinler075e5ba2020-02-21 15:46:00 -0600323 SRC src{*entry, ad, dataIface};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800324 EXPECT_TRUE(src.valid());
325
326 auto errorDetails = src.getErrorDetails(registry, DetailLevel::message);
327 ASSERT_TRUE(errorDetails);
Zane Shelley39936e32021-11-13 16:19:34 -0600328 EXPECT_EQ(errorDetails.value(),
329 "Comp 0x00000001 failed 0x00000004 times over 0x0000001E secs "
330 "with ErrorCode 0x01ABCDEF");
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800331}
Matt Spinlered046852020-03-13 13:58:15 -0500332// Test that an inventory path callout string is
333// converted into the appropriate FRU callout.
334TEST_F(SRCTest, InventoryCalloutTest)
335{
336 message::Entry entry;
337 entry.src.type = 0xBD;
338 entry.src.reasonCode = 0xABCD;
339 entry.subsystem = 0x42;
Matt Spinlered046852020-03-13 13:58:15 -0500340
341 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
342 AdditionalData ad{adData};
343 NiceMock<MockDataInterface> dataIface;
344
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500345 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
346 .WillOnce(Return("UTMS-P1"));
347
348 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500349 .Times(1)
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500350 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
351 SetArgReferee<3>("123456789ABC")));
Matt Spinlered046852020-03-13 13:58:15 -0500352
Sumit Kumar9d43a722021-08-24 09:46:19 -0500353 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
354 "system/entry"};
355 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
356 .WillOnce(Return(std::vector<bool>{false, false, false}));
357
Matt Spinlered046852020-03-13 13:58:15 -0500358 SRC src{entry, ad, dataIface};
359 EXPECT_TRUE(src.valid());
360
361 ASSERT_TRUE(src.callouts());
362
363 EXPECT_EQ(src.callouts()->callouts().size(), 1);
364
365 auto& callout = src.callouts()->callouts().front();
366
367 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
Matt Spinler717de422020-06-04 13:10:14 -0500368 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500369
370 auto& fru = callout->fruIdentity();
371
372 EXPECT_EQ(fru->getPN().value(), "1234567");
373 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
374 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
375
376 // flatten and unflatten
377 std::vector<uint8_t> data;
378 Stream stream{data};
379 src.flatten(stream);
380
381 stream.offset(0);
382 SRC newSRC{stream};
383 EXPECT_TRUE(newSRC.valid());
384 ASSERT_TRUE(src.callouts());
385 EXPECT_EQ(src.callouts()->callouts().size(), 1);
386}
387
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500388// Test that when the location code can't be obtained that
Matt Spinler479b6922021-08-17 16:34:59 -0500389// no callout is added.
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500390TEST_F(SRCTest, InventoryCalloutNoLocCodeTest)
391{
392 message::Entry entry;
393 entry.src.type = 0xBD;
394 entry.src.reasonCode = 0xABCD;
395 entry.subsystem = 0x42;
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500396
397 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
398 AdditionalData ad{adData};
399 NiceMock<MockDataInterface> dataIface;
400
401 auto func = []() {
402 throw sdbusplus::exception::SdBusError(5, "Error");
403 return std::string{};
404 };
405
406 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
407 .Times(1)
408 .WillOnce(InvokeWithoutArgs(func));
409
Sumit Kumar9d43a722021-08-24 09:46:19 -0500410 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
411 "system/entry"};
412 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
413 .WillOnce(Return(std::vector<bool>{false, false, false}));
414
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500415 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
416
417 SRC src{entry, ad, dataIface};
418 EXPECT_TRUE(src.valid());
419
Matt Spinler479b6922021-08-17 16:34:59 -0500420 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500421
422 // flatten and unflatten
423 std::vector<uint8_t> data;
424 Stream stream{data};
425 src.flatten(stream);
426
427 stream.offset(0);
428 SRC newSRC{stream};
429 EXPECT_TRUE(newSRC.valid());
Matt Spinler479b6922021-08-17 16:34:59 -0500430 ASSERT_FALSE(src.callouts());
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500431}
432
433// Test that when the VPD can't be obtained that
434// a callout is still created.
Matt Spinlered046852020-03-13 13:58:15 -0500435TEST_F(SRCTest, InventoryCalloutNoVPDTest)
436{
437 message::Entry entry;
438 entry.src.type = 0xBD;
439 entry.src.reasonCode = 0xABCD;
440 entry.subsystem = 0x42;
Matt Spinlered046852020-03-13 13:58:15 -0500441
442 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
443 AdditionalData ad{adData};
444 NiceMock<MockDataInterface> dataIface;
445
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500446 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
447 .Times(1)
448 .WillOnce(Return("UTMS-P10"));
449
Matt Spinlered046852020-03-13 13:58:15 -0500450 auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
451
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500452 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500453 .Times(1)
454 .WillOnce(InvokeWithoutArgs(func));
455
Sumit Kumar9d43a722021-08-24 09:46:19 -0500456 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
457 "system/entry"};
458 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
459 .WillOnce(Return(std::vector<bool>{false, false, false}));
460
Matt Spinlered046852020-03-13 13:58:15 -0500461 SRC src{entry, ad, dataIface};
462 EXPECT_TRUE(src.valid());
Matt Spinlered046852020-03-13 13:58:15 -0500463 ASSERT_TRUE(src.callouts());
Matt Spinlered046852020-03-13 13:58:15 -0500464 EXPECT_EQ(src.callouts()->callouts().size(), 1);
465
466 auto& callout = src.callouts()->callouts().front();
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500467 EXPECT_EQ(callout->locationCode(), "UTMS-P10");
Matt Spinler717de422020-06-04 13:10:14 -0500468 EXPECT_EQ(callout->priority(), 'H');
Matt Spinlered046852020-03-13 13:58:15 -0500469
470 auto& fru = callout->fruIdentity();
471
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500472 EXPECT_EQ(fru->getPN(), "");
473 EXPECT_EQ(fru->getCCIN(), "");
474 EXPECT_EQ(fru->getSN(), "");
475 EXPECT_FALSE(fru->getMaintProc());
476
Matt Spinlered046852020-03-13 13:58:15 -0500477 // flatten and unflatten
478 std::vector<uint8_t> data;
479 Stream stream{data};
480 src.flatten(stream);
481
482 stream.offset(0);
483 SRC newSRC{stream};
484 EXPECT_TRUE(newSRC.valid());
485 ASSERT_TRUE(src.callouts());
486 EXPECT_EQ(src.callouts()->callouts().size(), 1);
487}
Matt Spinler03984582020-04-09 13:17:58 -0500488
489TEST_F(SRCTest, RegistryCalloutTest)
490{
491 message::Entry entry;
492 entry.src.type = 0xBD;
493 entry.src.reasonCode = 0xABCD;
494 entry.subsystem = 0x42;
Matt Spinler03984582020-04-09 13:17:58 -0500495
496 entry.callouts = R"(
497 [
498 {
499 "System": "systemA",
500 "CalloutList":
501 [
502 {
503 "Priority": "high",
504 "SymbolicFRU": "service_docs"
505 },
506 {
507 "Priority": "medium",
Matt Spinler479b6922021-08-17 16:34:59 -0500508 "Procedure": "bmc_code"
Matt Spinler03984582020-04-09 13:17:58 -0500509 }
510 ]
511 },
512 {
513 "System": "systemB",
514 "CalloutList":
515 [
516 {
517 "Priority": "high",
518 "LocCode": "P0-C8",
519 "SymbolicFRUTrusted": "service_docs"
520 },
521 {
522 "Priority": "medium",
523 "SymbolicFRUTrusted": "service_docs"
524 }
525 ]
Matt Spinleraf191c72020-06-04 11:35:13 -0500526 },
527 {
528 "System": "systemC",
529 "CalloutList":
530 [
531 {
532 "Priority": "high",
533 "LocCode": "P0-C8"
534 },
535 {
536 "Priority": "medium",
537 "LocCode": "P0-C9"
538 }
539 ]
Matt Spinler03984582020-04-09 13:17:58 -0500540 }
541 ])"_json;
542
543 {
544 // Call out a symbolic FRU and a procedure
545 AdditionalData ad;
546 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500547 std::vector<std::string> names{"systemA"};
548
Matt Spinler1ab66962020-10-29 13:21:44 -0500549 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500550
Sumit Kumar9d43a722021-08-24 09:46:19 -0500551 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
552 "system/entry"};
553 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
554 .WillOnce(Return(std::vector<bool>{false, false, false}));
555
Matt Spinler03984582020-04-09 13:17:58 -0500556 SRC src{entry, ad, dataIface};
557
558 auto& callouts = src.callouts()->callouts();
559 ASSERT_EQ(callouts.size(), 2);
560
561 EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
562 EXPECT_EQ(callouts[0]->priority(), 'H');
563
564 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
565 EXPECT_EQ(callouts[1]->priority(), 'M');
566
567 auto& fru1 = callouts[0]->fruIdentity();
568 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
569 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
570 EXPECT_FALSE(fru1->getMaintProc());
571 EXPECT_FALSE(fru1->getSN());
572 EXPECT_FALSE(fru1->getCCIN());
573
574 auto& fru2 = callouts[1]->fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500575 EXPECT_EQ(fru2->getMaintProc().value(), "BMC0001");
Matt Spinler03984582020-04-09 13:17:58 -0500576 EXPECT_EQ(fru2->failingComponentType(),
577 src::FRUIdentity::maintenanceProc);
578 EXPECT_FALSE(fru2->getPN());
579 EXPECT_FALSE(fru2->getSN());
580 EXPECT_FALSE(fru2->getCCIN());
581 }
582
583 {
584 // Call out a trusted symbolic FRU with a location code, and
585 // another one without.
586 AdditionalData ad;
587 NiceMock<MockDataInterface> dataIface;
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500588 std::vector<std::string> names{"systemB"};
589
Matt Spinleraf191c72020-06-04 11:35:13 -0500590 EXPECT_CALL(dataIface, expandLocationCode).WillOnce(Return("P0-C8"));
Matt Spinler1ab66962020-10-29 13:21:44 -0500591 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinler03984582020-04-09 13:17:58 -0500592
Sumit Kumar9d43a722021-08-24 09:46:19 -0500593 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
594 "system/entry"};
595 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
596 .WillOnce(Return(std::vector<bool>{false, false, false}));
597
Matt Spinler03984582020-04-09 13:17:58 -0500598 SRC src{entry, ad, dataIface};
599
600 auto& callouts = src.callouts()->callouts();
601 EXPECT_EQ(callouts.size(), 2);
602
603 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
604 EXPECT_EQ(callouts[0]->priority(), 'H');
605
606 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
607 EXPECT_EQ(callouts[1]->priority(), 'M');
608
609 auto& fru1 = callouts[0]->fruIdentity();
610 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
611 EXPECT_EQ(fru1->failingComponentType(),
612 src::FRUIdentity::symbolicFRUTrustedLocCode);
613 EXPECT_FALSE(fru1->getMaintProc());
614 EXPECT_FALSE(fru1->getSN());
615 EXPECT_FALSE(fru1->getCCIN());
616
617 // It asked for a trusted symbolic FRU, but no location code
618 // was provided so it is switched back to a normal one
619 auto& fru2 = callouts[1]->fruIdentity();
620 EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
621 EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
622 EXPECT_FALSE(fru2->getMaintProc());
623 EXPECT_FALSE(fru2->getSN());
624 EXPECT_FALSE(fru2->getCCIN());
625 }
Matt Spinleraf191c72020-06-04 11:35:13 -0500626
627 {
628 // Two hardware callouts
629 AdditionalData ad;
630 NiceMock<MockDataInterface> dataIface;
631 std::vector<std::string> names{"systemC"};
632
Sumit Kumar9d43a722021-08-24 09:46:19 -0500633 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
634 "system/entry"};
635 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
636 .WillOnce(Return(std::vector<bool>{false, false, false}));
637
Matt Spinler1ab66962020-10-29 13:21:44 -0500638 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinleraf191c72020-06-04 11:35:13 -0500639
640 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
641 .WillOnce(Return("UXXX-P0-C8"));
642
643 EXPECT_CALL(dataIface, expandLocationCode("P0-C9", 0))
644 .WillOnce(Return("UXXX-P0-C9"));
645
Matt Spinler2f9225a2020-08-05 12:58:49 -0500646 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C8", 0, false))
Matt Spinleraf191c72020-06-04 11:35:13 -0500647 .WillOnce(Return(
648 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"));
649
Matt Spinler2f9225a2020-08-05 12:58:49 -0500650 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
Matt Spinleraf191c72020-06-04 11:35:13 -0500651 .WillOnce(Return(
652 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"));
653
654 EXPECT_CALL(
655 dataIface,
656 getHWCalloutFields(
657 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _,
658 _))
659 .Times(1)
660 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
661 SetArgReferee<2>("CCCC"),
662 SetArgReferee<3>("123456789ABC")));
663
664 EXPECT_CALL(
665 dataIface,
666 getHWCalloutFields(
667 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1", _, _,
668 _))
669 .Times(1)
670 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
671 SetArgReferee<2>("DDDD"),
672 SetArgReferee<3>("23456789ABCD")));
673
674 SRC src{entry, ad, dataIface};
675
676 auto& callouts = src.callouts()->callouts();
677 EXPECT_EQ(callouts.size(), 2);
678
679 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C8");
680 EXPECT_EQ(callouts[0]->priority(), 'H');
681
682 auto& fru1 = callouts[0]->fruIdentity();
683 EXPECT_EQ(fru1->getPN().value(), "1234567");
684 EXPECT_EQ(fru1->getCCIN().value(), "CCCC");
685 EXPECT_EQ(fru1->getSN().value(), "123456789ABC");
686
687 EXPECT_EQ(callouts[1]->locationCode(), "UXXX-P0-C9");
688 EXPECT_EQ(callouts[1]->priority(), 'M');
689
690 auto& fru2 = callouts[1]->fruIdentity();
691 EXPECT_EQ(fru2->getPN().value(), "2345678");
692 EXPECT_EQ(fru2->getCCIN().value(), "DDDD");
693 EXPECT_EQ(fru2->getSN().value(), "23456789ABCD");
694 }
Matt Spinler03984582020-04-09 13:17:58 -0500695}
Matt Spinler717de422020-06-04 13:10:14 -0500696
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500697// Test that a symbolic FRU with a trusted location code callout
698// from the registry can get its location from the
699// CALLOUT_INVENTORY_PATH AdditionalData entry.
700TEST_F(SRCTest, SymbolicFRUWithInvPathTest)
701{
702 message::Entry entry;
703 entry.src.type = 0xBD;
704 entry.src.reasonCode = 0xABCD;
705 entry.subsystem = 0x42;
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500706
707 entry.callouts = R"(
708 [{
709 "CalloutList":
710 [
711 {
712 "Priority": "high",
713 "SymbolicFRUTrusted": "service_docs",
714 "UseInventoryLocCode": true
715 },
716 {
717 "Priority": "medium",
718 "LocCode": "P0-C8",
719 "SymbolicFRUTrusted": "pwrsply"
720 }
721 ]
722 }])"_json;
723
724 {
725 // The location code for the first symbolic FRU callout will
726 // come from this inventory path since UseInventoryLocCode is set.
727 // In this case there will be no normal FRU callout for the motherboard.
728 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
729 AdditionalData ad{adData};
730 NiceMock<MockDataInterface> dataIface;
731 std::vector<std::string> names{"systemA"};
732
Sumit Kumar9d43a722021-08-24 09:46:19 -0500733 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
734 "system/entry"};
735 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
736 .WillOnce(Return(std::vector<bool>{false, false, false}));
737
Matt Spinler1ab66962020-10-29 13:21:44 -0500738 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500739
740 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
741 .Times(1)
742 .WillOnce(Return("Ufcs-P10"));
743
744 EXPECT_CALL(dataIface, expandLocationCode("P0-C8", 0))
745 .WillOnce(Return("Ufcs-P0-C8"));
746
747 SRC src{entry, ad, dataIface};
748
749 auto& callouts = src.callouts()->callouts();
750 EXPECT_EQ(callouts.size(), 2);
751
752 // The location code for the first symbolic FRU callout with a
753 // trusted location code comes from the motherboard.
754 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P10");
755 EXPECT_EQ(callouts[0]->priority(), 'H');
756 auto& fru1 = callouts[0]->fruIdentity();
757 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
758 EXPECT_EQ(fru1->failingComponentType(),
759 src::FRUIdentity::symbolicFRUTrustedLocCode);
760
761 // The second trusted symbolic FRU callouts uses the location
762 // code in the registry as usual.
763 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P0-C8");
764 EXPECT_EQ(callouts[1]->priority(), 'M');
765 auto& fru2 = callouts[1]->fruIdentity();
766 EXPECT_EQ(fru2->getPN().value(), "PWRSPLY");
767 EXPECT_EQ(fru2->failingComponentType(),
768 src::FRUIdentity::symbolicFRUTrustedLocCode);
769 }
770
771 {
772 // This time say we want to use the location code from
773 // the inventory, but don't pass it in and the callout should
774 // end up a regular symbolic FRU
775 entry.callouts = R"(
776 [{
777 "CalloutList":
778 [
779 {
780 "Priority": "high",
781 "SymbolicFRUTrusted": "service_docs",
782 "UseInventoryLocCode": true
783 }
784 ]
785 }])"_json;
786
787 AdditionalData ad;
788 NiceMock<MockDataInterface> dataIface;
789 std::vector<std::string> names{"systemA"};
790
Sumit Kumar9d43a722021-08-24 09:46:19 -0500791 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
792 "system/entry"};
793 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
794 .WillOnce(Return(std::vector<bool>{false, false, false}));
795
Matt Spinler1ab66962020-10-29 13:21:44 -0500796 EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500797
798 SRC src{entry, ad, dataIface};
799
800 auto& callouts = src.callouts()->callouts();
801 EXPECT_EQ(callouts.size(), 1);
802
803 EXPECT_EQ(callouts[0]->locationCode(), "");
804 EXPECT_EQ(callouts[0]->priority(), 'H');
805 auto& fru1 = callouts[0]->fruIdentity();
806 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
807 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
808 }
809}
810
Matt Spinler717de422020-06-04 13:10:14 -0500811// Test looking up device path fails in the callout jSON.
812TEST_F(SRCTest, DevicePathCalloutTest)
813{
814 message::Entry entry;
815 entry.src.type = 0xBD;
816 entry.src.reasonCode = 0xABCD;
817 entry.subsystem = 0x42;
Matt Spinler717de422020-06-04 13:10:14 -0500818
819 const auto calloutJSON = R"(
820 {
821 "I2C":
822 {
823 "14":
824 {
825 "114":
826 {
827 "Callouts":[
828 {
829 "Name": "/chassis/motherboard/cpu0",
830 "LocationCode": "P1-C40",
831 "Priority": "H"
832 },
833 {
834 "Name": "/chassis/motherboard",
835 "LocationCode": "P1",
836 "Priority": "M"
837 },
838 {
839 "Name": "/chassis/motherboard/bmc",
840 "LocationCode": "P1-C15",
841 "Priority": "L"
842 }
843 ],
844 "Dest": "proc 0 target"
845 }
846 }
847 }
848 })";
849
850 auto dataPath = getPELReadOnlyDataPath();
851 std::ofstream file{dataPath / "systemA_dev_callouts.json"};
852 file << calloutJSON;
853 file.close();
854
855 NiceMock<MockDataInterface> dataIface;
856 std::vector<std::string> names{"systemA"};
857
Sumit Kumar9d43a722021-08-24 09:46:19 -0500858 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
859 "system/entry"};
860 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
861 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
862
Matt Spinler717de422020-06-04 13:10:14 -0500863 EXPECT_CALL(dataIface, getSystemNames)
864 .Times(5)
Matt Spinler1ab66962020-10-29 13:21:44 -0500865 .WillRepeatedly(Return(names));
Matt Spinler717de422020-06-04 13:10:14 -0500866
Matt Spinler2f9225a2020-08-05 12:58:49 -0500867 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C40", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500868 .Times(3)
869 .WillRepeatedly(
870 Return("/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"));
871
Matt Spinler2f9225a2020-08-05 12:58:49 -0500872 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500873 .Times(3)
874 .WillRepeatedly(
875 Return("/xyz/openbmc_project/inventory/chassis/motherboard"));
876
Matt Spinler2f9225a2020-08-05 12:58:49 -0500877 EXPECT_CALL(dataIface, getInventoryFromLocCode("P1-C15", 0, false))
Matt Spinler717de422020-06-04 13:10:14 -0500878 .Times(3)
879 .WillRepeatedly(
880 Return("/xyz/openbmc_project/inventory/chassis/motherboard/bmc"));
881
Matt Spinler0d92b522021-06-16 13:28:17 -0600882 EXPECT_CALL(dataIface, expandLocationCode("P1-C40", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500883 .Times(3)
884 .WillRepeatedly(Return("Ufcs-P1-C40"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600885
886 EXPECT_CALL(dataIface, expandLocationCode("P1", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500887 .Times(3)
888 .WillRepeatedly(Return("Ufcs-P1"));
Matt Spinler0d92b522021-06-16 13:28:17 -0600889
890 EXPECT_CALL(dataIface, expandLocationCode("P1-C15", 0))
Matt Spinler717de422020-06-04 13:10:14 -0500891 .Times(3)
892 .WillRepeatedly(Return("Ufcs-P1-C15"));
893
894 EXPECT_CALL(
895 dataIface,
896 getHWCalloutFields(
897 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0", _, _, _))
898 .Times(3)
899 .WillRepeatedly(DoAll(SetArgReferee<1>("1234567"),
900 SetArgReferee<2>("CCCC"),
901 SetArgReferee<3>("123456789ABC")));
902 EXPECT_CALL(
903 dataIface,
904 getHWCalloutFields("/xyz/openbmc_project/inventory/chassis/motherboard",
905 _, _, _))
906 .Times(3)
907 .WillRepeatedly(DoAll(SetArgReferee<1>("7654321"),
908 SetArgReferee<2>("MMMM"),
909 SetArgReferee<3>("CBA987654321")));
910 EXPECT_CALL(
911 dataIface,
912 getHWCalloutFields(
913 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc", _, _, _))
914 .Times(3)
915 .WillRepeatedly(DoAll(SetArgReferee<1>("7123456"),
916 SetArgReferee<2>("BBBB"),
917 SetArgReferee<3>("C123456789AB")));
918
919 // Call this below with different AdditionalData values that
920 // result in the same callouts.
921 auto checkCallouts = [&entry, &dataIface](const auto& items) {
922 AdditionalData ad{items};
923 SRC src{entry, ad, dataIface};
924
925 ASSERT_TRUE(src.callouts());
926 auto& callouts = src.callouts()->callouts();
927
928 ASSERT_EQ(callouts.size(), 3);
929
930 {
931 EXPECT_EQ(callouts[0]->priority(), 'H');
932 EXPECT_EQ(callouts[0]->locationCode(), "Ufcs-P1-C40");
933
934 auto& fru = callouts[0]->fruIdentity();
935 EXPECT_EQ(fru->getPN().value(), "1234567");
936 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
937 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
938 }
939 {
940 EXPECT_EQ(callouts[1]->priority(), 'M');
941 EXPECT_EQ(callouts[1]->locationCode(), "Ufcs-P1");
942
943 auto& fru = callouts[1]->fruIdentity();
944 EXPECT_EQ(fru->getPN().value(), "7654321");
945 EXPECT_EQ(fru->getCCIN().value(), "MMMM");
946 EXPECT_EQ(fru->getSN().value(), "CBA987654321");
947 }
948 {
949 EXPECT_EQ(callouts[2]->priority(), 'L');
950 EXPECT_EQ(callouts[2]->locationCode(), "Ufcs-P1-C15");
951
952 auto& fru = callouts[2]->fruIdentity();
953 EXPECT_EQ(fru->getPN().value(), "7123456");
954 EXPECT_EQ(fru->getCCIN().value(), "BBBB");
955 EXPECT_EQ(fru->getSN().value(), "C123456789AB");
956 }
957 };
958
959 {
960 // Callouts based on the device path
961 std::vector<std::string> items{
962 "CALLOUT_ERRNO=5",
963 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
964 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-14/14-0072"};
965
966 checkCallouts(items);
967 }
968
969 {
970 // Callouts based on the I2C bus and address
971 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
972 "CALLOUT_IIC_ADDR=0x72"};
973 checkCallouts(items);
974 }
975
976 {
977 // Also based on I2C bus and address, but with bus = /dev/i2c-14
978 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=14",
979 "CALLOUT_IIC_ADDR=0x72"};
980 checkCallouts(items);
981 }
982
983 {
984 // Callout not found
985 std::vector<std::string> items{
986 "CALLOUT_ERRNO=5",
987 "CALLOUT_DEVICE_PATH=/sys/devices/platform/ahb/ahb:apb/"
988 "ahb:apb:bus@1e78a000/1e78a340.i2c-bus/i2c-24/24-0012"};
989
990 AdditionalData ad{items};
991 SRC src{entry, ad, dataIface};
992
993 EXPECT_FALSE(src.callouts());
994 ASSERT_EQ(src.getDebugData().size(), 1);
995 EXPECT_EQ(src.getDebugData()[0],
996 "Problem looking up I2C callouts on 24 18: "
997 "[json.exception.out_of_range.403] key '24' not found");
998 }
999
1000 {
1001 // Callout not found
1002 std::vector<std::string> items{"CALLOUT_ERRNO=5", "CALLOUT_IIC_BUS=22",
1003 "CALLOUT_IIC_ADDR=0x99"};
1004 AdditionalData ad{items};
1005 SRC src{entry, ad, dataIface};
1006
1007 EXPECT_FALSE(src.callouts());
1008 ASSERT_EQ(src.getDebugData().size(), 1);
1009 EXPECT_EQ(src.getDebugData()[0],
1010 "Problem looking up I2C callouts on 22 153: "
1011 "[json.exception.out_of_range.403] key '22' not found");
1012 }
1013
1014 fs::remove_all(dataPath);
1015}
Matt Spinler3bdd0112020-08-27 10:24:34 -05001016
1017// Test when callouts are passed in via JSON
1018TEST_F(SRCTest, JsonCalloutsTest)
1019{
1020 const auto jsonCallouts = R"(
1021 [
1022 {
1023 "LocationCode": "P0-C1",
1024 "Priority": "H",
1025 "MRUs": [
1026 {
1027 "ID": 42,
1028 "Priority": "H"
1029 },
1030 {
1031 "ID": 43,
1032 "Priority": "M"
1033 }
1034 ]
1035 },
1036 {
1037 "InventoryPath": "/inv/system/chassis/motherboard/cpu0",
1038 "Priority": "M",
1039 "Guarded": true,
1040 "Deconfigured": true
1041 },
1042 {
1043 "Procedure": "PROCEDU",
1044 "Priority": "A"
1045 },
1046 {
1047 "SymbolicFRU": "TRUSTED",
1048 "Priority": "B",
1049 "TrustedLocationCode": true,
1050 "LocationCode": "P1-C23"
1051 },
1052 {
1053 "SymbolicFRU": "FRUTST1",
1054 "Priority": "C",
1055 "LocationCode": "P1-C24"
1056 },
1057 {
1058 "SymbolicFRU": "FRUTST2LONG",
1059 "Priority": "L"
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001060 },
1061 {
1062 "Procedure": "fsi_path",
1063 "Priority": "L"
1064 },
1065 {
1066 "SymbolicFRU": "ambient_temp",
1067 "Priority": "L"
Matt Spinler3bdd0112020-08-27 10:24:34 -05001068 }
1069 ]
1070 )"_json;
1071
1072 message::Entry entry;
1073 entry.src.type = 0xBD;
1074 entry.src.reasonCode = 0xABCD;
1075 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001076
1077 AdditionalData ad;
1078 NiceMock<MockDataInterface> dataIface;
1079
Sumit Kumar9d43a722021-08-24 09:46:19 -05001080 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1081 "system/entry"};
1082 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1083 .WillOnce(Return(std::vector<bool>{false, false, false}));
1084
Matt Spinler3bdd0112020-08-27 10:24:34 -05001085 // Callout 0 mock calls
1086 {
1087 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1088 .Times(1)
1089 .WillOnce(Return("UXXX-P0-C1"));
1090 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1091 .Times(1)
1092 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1093 EXPECT_CALL(
1094 dataIface,
1095 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1096 .Times(1)
1097 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1098 SetArgReferee<2>("CCCC"),
1099 SetArgReferee<3>("123456789ABC")));
1100 }
1101 // Callout 1 mock calls
1102 {
1103 EXPECT_CALL(dataIface,
1104 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1105 .WillOnce(Return("UYYY-P5"));
1106 EXPECT_CALL(
1107 dataIface,
1108 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1109 .Times(1)
1110 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
1111 SetArgReferee<2>("DDDD"),
1112 SetArgReferee<3>("23456789ABCD")));
1113 }
1114 // Callout 3 mock calls
1115 {
1116 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1117 .Times(1)
1118 .WillOnce(Return("UXXX-P1-C23"));
1119 }
1120 // Callout 4 mock calls
1121 {
1122 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1123 .Times(1)
1124 .WillOnce(Return("UXXX-P1-C24"));
1125 }
1126
1127 SRC src{entry, ad, jsonCallouts, dataIface};
1128 ASSERT_TRUE(src.callouts());
1129
Matt Spinlerafa2c792020-08-27 11:01:39 -05001130 // Check the guarded and deconfigured flags
1131 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1132
Matt Spinler3bdd0112020-08-27 10:24:34 -05001133 const auto& callouts = src.callouts()->callouts();
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001134 ASSERT_EQ(callouts.size(), 8);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001135
1136 // Check callout 0
1137 {
1138 EXPECT_EQ(callouts[0]->priority(), 'H');
1139 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1140
1141 auto& fru = callouts[0]->fruIdentity();
1142 EXPECT_EQ(fru->getPN().value(), "1234567");
1143 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1144 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1145 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001146
1147 auto& mruCallouts = callouts[0]->mru();
1148 ASSERT_TRUE(mruCallouts);
1149 auto& mrus = mruCallouts->mrus();
1150 ASSERT_EQ(mrus.size(), 2);
1151 EXPECT_EQ(mrus[0].id, 42);
1152 EXPECT_EQ(mrus[0].priority, 'H');
1153 EXPECT_EQ(mrus[1].id, 43);
1154 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001155 }
1156
1157 // Check callout 1
1158 {
1159 EXPECT_EQ(callouts[1]->priority(), 'M');
1160 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1161
1162 auto& fru = callouts[1]->fruIdentity();
1163 EXPECT_EQ(fru->getPN().value(), "2345678");
1164 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1165 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1166 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1167 }
1168
1169 // Check callout 2
1170 {
1171 EXPECT_EQ(callouts[2]->priority(), 'A');
1172 EXPECT_EQ(callouts[2]->locationCode(), "");
1173
1174 auto& fru = callouts[2]->fruIdentity();
1175 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1176 EXPECT_EQ(fru->failingComponentType(),
1177 src::FRUIdentity::maintenanceProc);
1178 }
1179
1180 // Check callout 3
1181 {
1182 EXPECT_EQ(callouts[3]->priority(), 'B');
1183 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1184
1185 auto& fru = callouts[3]->fruIdentity();
1186 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1187 EXPECT_EQ(fru->failingComponentType(),
1188 src::FRUIdentity::symbolicFRUTrustedLocCode);
1189 }
1190
1191 // Check callout 4
1192 {
1193 EXPECT_EQ(callouts[4]->priority(), 'C');
1194 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1195
1196 auto& fru = callouts[4]->fruIdentity();
1197 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1198 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1199 }
1200
1201 // Check callout 5
1202 {
1203 EXPECT_EQ(callouts[5]->priority(), 'L');
1204 EXPECT_EQ(callouts[5]->locationCode(), "");
1205
1206 auto& fru = callouts[5]->fruIdentity();
1207 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1208 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1209 }
1210
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001211 // Check callout 6
1212 {
1213 EXPECT_EQ(callouts[6]->priority(), 'L');
1214 EXPECT_EQ(callouts[6]->locationCode(), "");
1215
1216 auto& fru = callouts[6]->fruIdentity();
1217 EXPECT_EQ(fru->getMaintProc().value(), "BMC0004");
1218 EXPECT_EQ(fru->failingComponentType(),
1219 src::FRUIdentity::maintenanceProc);
1220 }
1221
1222 // Check callout 7
1223 {
1224 EXPECT_EQ(callouts[7]->priority(), 'L');
1225 EXPECT_EQ(callouts[7]->locationCode(), "");
1226
1227 auto& fru = callouts[7]->fruIdentity();
1228 EXPECT_EQ(fru->getPN().value(), "AMBTEMP");
1229 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1230 }
1231
Matt Spinler3bdd0112020-08-27 10:24:34 -05001232 // Check that it didn't find any errors
1233 const auto& data = src.getDebugData();
1234 EXPECT_TRUE(data.empty());
1235}
1236
1237TEST_F(SRCTest, JsonBadCalloutsTest)
1238{
1239 // The first call will have a Throw in a mock call.
1240 // The second will have a different Throw in a mock call.
1241 // The others have issues with the Priority field.
1242 const auto jsonCallouts = R"(
1243 [
1244 {
1245 "LocationCode": "P0-C1",
1246 "Priority": "H"
1247 },
1248 {
1249 "LocationCode": "P0-C2",
1250 "Priority": "H"
1251 },
1252 {
1253 "LocationCode": "P0-C3"
1254 },
1255 {
1256 "LocationCode": "P0-C4",
1257 "Priority": "X"
1258 }
1259 ]
1260 )"_json;
1261
1262 message::Entry entry;
1263 entry.src.type = 0xBD;
1264 entry.src.reasonCode = 0xABCD;
1265 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001266
1267 AdditionalData ad;
1268 NiceMock<MockDataInterface> dataIface;
1269
Sumit Kumar9d43a722021-08-24 09:46:19 -05001270 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1271 "system/entry"};
1272 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1273 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
1274
Matt Spinler3bdd0112020-08-27 10:24:34 -05001275 // Callout 0 mock calls
1276 // Expand location code will fail, so the unexpanded location
1277 // code should show up in the callout instead.
1278 {
1279 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1280 .WillOnce(Throw(std::runtime_error("Fail")));
1281
1282 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1283 .Times(1)
1284 .WillOnce(Return("/inv/system/chassis/motherboard/bmc"));
1285 EXPECT_CALL(
1286 dataIface,
1287 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1288 .Times(1)
1289 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1290 SetArgReferee<2>("CCCC"),
1291 SetArgReferee<3>("123456789ABC")));
1292 }
1293
1294 // Callout 1 mock calls
1295 // getInventoryFromLocCode will fail
1296 {
1297 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1298 .Times(1)
1299 .WillOnce(Return("UXXX-P0-C2"));
1300
1301 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1302 .Times(1)
1303 .WillOnce(Throw(std::runtime_error("Fail")));
1304 }
1305
1306 SRC src{entry, ad, jsonCallouts, dataIface};
1307
1308 ASSERT_TRUE(src.callouts());
1309
1310 const auto& callouts = src.callouts()->callouts();
1311
1312 // Only the first callout was successful
1313 ASSERT_EQ(callouts.size(), 1);
1314
1315 {
1316 EXPECT_EQ(callouts[0]->priority(), 'H');
1317 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
1318
1319 auto& fru = callouts[0]->fruIdentity();
1320 EXPECT_EQ(fru->getPN().value(), "1234567");
1321 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1322 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1323 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1324 }
1325
1326 const auto& data = src.getDebugData();
1327 ASSERT_EQ(data.size(), 4);
1328 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
1329 EXPECT_STREQ(data[1].c_str(),
1330 "Failed extracting callout data from JSON: Unable to "
1331 "get inventory path from location code: P0-C2: Fail");
1332 EXPECT_STREQ(data[2].c_str(),
1333 "Failed extracting callout data from JSON: "
1334 "[json.exception.out_of_range.403] key 'Priority' not found");
1335 EXPECT_STREQ(data[3].c_str(),
1336 "Failed extracting callout data from JSON: Invalid "
1337 "priority 'X' found in JSON callout");
1338}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001339
1340// Test that an inventory path callout can have
1341// a different priority than H.
1342TEST_F(SRCTest, InventoryCalloutTestPriority)
1343{
1344 message::Entry entry;
1345 entry.src.type = 0xBD;
1346 entry.src.reasonCode = 0xABCD;
1347 entry.subsystem = 0x42;
Miguel Gomez53ef1552020-10-14 21:16:32 +00001348
1349 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard",
1350 "CALLOUT_PRIORITY=M"};
1351 AdditionalData ad{adData};
1352 NiceMock<MockDataInterface> dataIface;
1353
Sumit Kumar9d43a722021-08-24 09:46:19 -05001354 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1355 "system/entry"};
1356 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1357 .WillOnce(Return(std::vector<bool>{false, false, false}));
1358
Miguel Gomez53ef1552020-10-14 21:16:32 +00001359 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1360 .WillOnce(Return("UTMS-P1"));
1361
1362 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1363 .Times(1)
1364 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1365 SetArgReferee<3>("123456789ABC")));
1366
1367 SRC src{entry, ad, dataIface};
1368 EXPECT_TRUE(src.valid());
1369
1370 ASSERT_TRUE(src.callouts());
1371
1372 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1373
1374 auto& callout = src.callouts()->callouts().front();
1375
1376 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1377 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001378}
Sumit Kumar9d43a722021-08-24 09:46:19 -05001379
1380// Test for bmc & platform dump status bits
1381TEST_F(SRCTest, DumpStatusBitsCheck)
1382{
1383 message::Entry entry;
1384 entry.src.type = 0xBD;
1385 entry.src.reasonCode = 0xABCD;
1386 entry.subsystem = 0x42;
Sumit Kumar9d43a722021-08-24 09:46:19 -05001387
1388 AdditionalData ad;
1389 NiceMock<MockDataInterface> dataIface;
1390 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1391 "system/entry"};
1392
1393 {
1394 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1395 .WillOnce(Return(std::vector<bool>{true, false, false}));
1396
1397 SRC src{entry, ad, dataIface};
1398 EXPECT_TRUE(src.valid());
1399
1400 const auto& hexwords = src.hexwordData();
1401 EXPECT_EQ(0x00080055, hexwords[0]);
1402 }
1403
1404 {
1405 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1406 .WillOnce(Return(std::vector<bool>{false, true, false}));
1407
1408 SRC src{entry, ad, dataIface};
1409 EXPECT_TRUE(src.valid());
1410
1411 const auto& hexwords = src.hexwordData();
1412 EXPECT_EQ(0x00000255, hexwords[0]);
1413 }
1414
1415 {
1416 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1417 .WillOnce(Return(std::vector<bool>{false, false, true}));
1418
1419 SRC src{entry, ad, dataIface};
1420 EXPECT_TRUE(src.valid());
1421
1422 const auto& hexwords = src.hexwordData();
1423 EXPECT_EQ(0x00000455, hexwords[0]);
1424 }
1425
1426 {
1427 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1428 .WillOnce(Return(std::vector<bool>{true, true, true}));
1429
1430 SRC src{entry, ad, dataIface};
1431 EXPECT_TRUE(src.valid());
1432
1433 const auto& hexwords = src.hexwordData();
1434 EXPECT_EQ(0x00080655, hexwords[0]);
1435 }
1436}
Sumit Kumar50bfa692022-01-06 06:48:26 -06001437
1438// Test SRC with additional data - PEL_SUBSYSTEM
1439TEST_F(SRCTest, TestPELSubsystem)
1440{
1441 message::Entry entry;
1442 entry.src.type = 0xBD;
1443 entry.src.reasonCode = 0xABCD;
1444 entry.subsystem = 0x42;
Sumit Kumar50bfa692022-01-06 06:48:26 -06001445
1446 // Values for the SRC words pointed to above
1447 std::vector<std::string> adData{"PEL_SUBSYSTEM=0x20"};
1448 AdditionalData ad{adData};
1449 NiceMock<MockDataInterface> dataIface;
1450
1451 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
1452
1453 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1454 "system/entry"};
1455 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1456 .WillOnce(Return(std::vector<bool>{false, false, false}));
1457
1458 SRC src{entry, ad, dataIface};
1459
1460 EXPECT_TRUE(src.valid());
1461
1462 EXPECT_EQ(src.asciiString(), "BD20ABCD ");
1463}