blob: f2ade6825aa5d03d97c8a3f66a94131defdbcfe3 [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 Spinlerbad056b2023-01-25 14:16:57 -0600647 .WillOnce(Return(std::vector<std::string>{
648 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
Matt Spinleraf191c72020-06-04 11:35:13 -0500649
Matt Spinler2f9225a2020-08-05 12:58:49 -0500650 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C9", 0, false))
Matt Spinlerbad056b2023-01-25 14:16:57 -0600651 .WillOnce(Return(std::vector<std::string>{
652 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu1"}));
Matt Spinleraf191c72020-06-04 11:35:13 -0500653
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)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600869 .WillRepeatedly(Return(std::vector<std::string>{
870 "/xyz/openbmc_project/inventory/chassis/motherboard/cpu0"}));
Matt Spinler717de422020-06-04 13:10:14 -0500871
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)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600874 .WillRepeatedly(Return(std::vector<std::string>{
875 "/xyz/openbmc_project/inventory/chassis/motherboard"}));
Matt Spinler717de422020-06-04 13:10:14 -0500876
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)
Matt Spinlerbad056b2023-01-25 14:16:57 -0600879 .WillRepeatedly(Return(std::vector<std::string>{
880 "/xyz/openbmc_project/inventory/chassis/motherboard/bmc"}));
Matt Spinler717de422020-06-04 13:10:14 -0500881
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)
Matt Spinlerbad056b2023-01-25 14:16:57 -06001092 .WillOnce(Return(std::vector<std::string>{
1093 "/inv/system/chassis/motherboard/bmc"}));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001094 EXPECT_CALL(
1095 dataIface,
1096 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1097 .Times(1)
1098 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1099 SetArgReferee<2>("CCCC"),
1100 SetArgReferee<3>("123456789ABC")));
1101 }
1102 // Callout 1 mock calls
1103 {
1104 EXPECT_CALL(dataIface,
1105 getLocationCode("/inv/system/chassis/motherboard/cpu0"))
1106 .WillOnce(Return("UYYY-P5"));
1107 EXPECT_CALL(
1108 dataIface,
1109 getHWCalloutFields("/inv/system/chassis/motherboard/cpu0", _, _, _))
1110 .Times(1)
1111 .WillOnce(DoAll(SetArgReferee<1>("2345678"),
1112 SetArgReferee<2>("DDDD"),
1113 SetArgReferee<3>("23456789ABCD")));
1114 }
1115 // Callout 3 mock calls
1116 {
1117 EXPECT_CALL(dataIface, expandLocationCode("P1-C23", 0))
1118 .Times(1)
1119 .WillOnce(Return("UXXX-P1-C23"));
1120 }
1121 // Callout 4 mock calls
1122 {
1123 EXPECT_CALL(dataIface, expandLocationCode("P1-C24", 0))
1124 .Times(1)
1125 .WillOnce(Return("UXXX-P1-C24"));
1126 }
1127
1128 SRC src{entry, ad, jsonCallouts, dataIface};
1129 ASSERT_TRUE(src.callouts());
1130
Matt Spinlerafa2c792020-08-27 11:01:39 -05001131 // Check the guarded and deconfigured flags
1132 EXPECT_TRUE(src.hexwordData()[3] & 0x03000000);
1133
Matt Spinler3bdd0112020-08-27 10:24:34 -05001134 const auto& callouts = src.callouts()->callouts();
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001135 ASSERT_EQ(callouts.size(), 8);
Matt Spinler3bdd0112020-08-27 10:24:34 -05001136
1137 // Check callout 0
1138 {
1139 EXPECT_EQ(callouts[0]->priority(), 'H');
1140 EXPECT_EQ(callouts[0]->locationCode(), "UXXX-P0-C1");
1141
1142 auto& fru = callouts[0]->fruIdentity();
1143 EXPECT_EQ(fru->getPN().value(), "1234567");
1144 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1145 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1146 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001147
1148 auto& mruCallouts = callouts[0]->mru();
1149 ASSERT_TRUE(mruCallouts);
1150 auto& mrus = mruCallouts->mrus();
1151 ASSERT_EQ(mrus.size(), 2);
1152 EXPECT_EQ(mrus[0].id, 42);
1153 EXPECT_EQ(mrus[0].priority, 'H');
1154 EXPECT_EQ(mrus[1].id, 43);
1155 EXPECT_EQ(mrus[1].priority, 'M');
Matt Spinler3bdd0112020-08-27 10:24:34 -05001156 }
1157
1158 // Check callout 1
1159 {
1160 EXPECT_EQ(callouts[1]->priority(), 'M');
1161 EXPECT_EQ(callouts[1]->locationCode(), "UYYY-P5");
1162
1163 auto& fru = callouts[1]->fruIdentity();
1164 EXPECT_EQ(fru->getPN().value(), "2345678");
1165 EXPECT_EQ(fru->getCCIN().value(), "DDDD");
1166 EXPECT_EQ(fru->getSN().value(), "23456789ABCD");
1167 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1168 }
1169
1170 // Check callout 2
1171 {
1172 EXPECT_EQ(callouts[2]->priority(), 'A');
1173 EXPECT_EQ(callouts[2]->locationCode(), "");
1174
1175 auto& fru = callouts[2]->fruIdentity();
1176 EXPECT_EQ(fru->getMaintProc().value(), "PROCEDU");
1177 EXPECT_EQ(fru->failingComponentType(),
1178 src::FRUIdentity::maintenanceProc);
1179 }
1180
1181 // Check callout 3
1182 {
1183 EXPECT_EQ(callouts[3]->priority(), 'B');
1184 EXPECT_EQ(callouts[3]->locationCode(), "UXXX-P1-C23");
1185
1186 auto& fru = callouts[3]->fruIdentity();
1187 EXPECT_EQ(fru->getPN().value(), "TRUSTED");
1188 EXPECT_EQ(fru->failingComponentType(),
1189 src::FRUIdentity::symbolicFRUTrustedLocCode);
1190 }
1191
1192 // Check callout 4
1193 {
1194 EXPECT_EQ(callouts[4]->priority(), 'C');
1195 EXPECT_EQ(callouts[4]->locationCode(), "UXXX-P1-C24");
1196
1197 auto& fru = callouts[4]->fruIdentity();
1198 EXPECT_EQ(fru->getPN().value(), "FRUTST1");
1199 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1200 }
1201
1202 // Check callout 5
1203 {
1204 EXPECT_EQ(callouts[5]->priority(), 'L');
1205 EXPECT_EQ(callouts[5]->locationCode(), "");
1206
1207 auto& fru = callouts[5]->fruIdentity();
1208 EXPECT_EQ(fru->getPN().value(), "FRUTST2");
1209 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1210 }
1211
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001212 // Check callout 6
1213 {
1214 EXPECT_EQ(callouts[6]->priority(), 'L');
1215 EXPECT_EQ(callouts[6]->locationCode(), "");
1216
1217 auto& fru = callouts[6]->fruIdentity();
1218 EXPECT_EQ(fru->getMaintProc().value(), "BMC0004");
1219 EXPECT_EQ(fru->failingComponentType(),
1220 src::FRUIdentity::maintenanceProc);
1221 }
1222
1223 // Check callout 7
1224 {
1225 EXPECT_EQ(callouts[7]->priority(), 'L');
1226 EXPECT_EQ(callouts[7]->locationCode(), "");
1227
1228 auto& fru = callouts[7]->fruIdentity();
1229 EXPECT_EQ(fru->getPN().value(), "AMBTEMP");
1230 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::symbolicFRU);
1231 }
1232
Matt Spinler3bdd0112020-08-27 10:24:34 -05001233 // Check that it didn't find any errors
1234 const auto& data = src.getDebugData();
1235 EXPECT_TRUE(data.empty());
1236}
1237
1238TEST_F(SRCTest, JsonBadCalloutsTest)
1239{
1240 // The first call will have a Throw in a mock call.
1241 // The second will have a different Throw in a mock call.
1242 // The others have issues with the Priority field.
1243 const auto jsonCallouts = R"(
1244 [
1245 {
1246 "LocationCode": "P0-C1",
1247 "Priority": "H"
1248 },
1249 {
1250 "LocationCode": "P0-C2",
1251 "Priority": "H"
1252 },
1253 {
1254 "LocationCode": "P0-C3"
1255 },
1256 {
1257 "LocationCode": "P0-C4",
1258 "Priority": "X"
1259 }
1260 ]
1261 )"_json;
1262
1263 message::Entry entry;
1264 entry.src.type = 0xBD;
1265 entry.src.reasonCode = 0xABCD;
1266 entry.subsystem = 0x42;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001267
1268 AdditionalData ad;
1269 NiceMock<MockDataInterface> dataIface;
1270
Sumit Kumar9d43a722021-08-24 09:46:19 -05001271 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1272 "system/entry"};
1273 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1274 .WillRepeatedly(Return(std::vector<bool>{false, false, false}));
1275
Matt Spinler3bdd0112020-08-27 10:24:34 -05001276 // Callout 0 mock calls
1277 // Expand location code will fail, so the unexpanded location
1278 // code should show up in the callout instead.
1279 {
1280 EXPECT_CALL(dataIface, expandLocationCode("P0-C1", 0))
1281 .WillOnce(Throw(std::runtime_error("Fail")));
1282
1283 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C1", 0, false))
1284 .Times(1)
Matt Spinlerbad056b2023-01-25 14:16:57 -06001285 .WillOnce(Return(std::vector<std::string>{
1286 "/inv/system/chassis/motherboard/bmc"}));
Matt Spinler3bdd0112020-08-27 10:24:34 -05001287 EXPECT_CALL(
1288 dataIface,
1289 getHWCalloutFields("/inv/system/chassis/motherboard/bmc", _, _, _))
1290 .Times(1)
1291 .WillOnce(DoAll(SetArgReferee<1>("1234567"),
1292 SetArgReferee<2>("CCCC"),
1293 SetArgReferee<3>("123456789ABC")));
1294 }
1295
1296 // Callout 1 mock calls
1297 // getInventoryFromLocCode will fail
1298 {
1299 EXPECT_CALL(dataIface, expandLocationCode("P0-C2", 0))
1300 .Times(1)
1301 .WillOnce(Return("UXXX-P0-C2"));
1302
1303 EXPECT_CALL(dataIface, getInventoryFromLocCode("P0-C2", 0, false))
1304 .Times(1)
1305 .WillOnce(Throw(std::runtime_error("Fail")));
1306 }
1307
1308 SRC src{entry, ad, jsonCallouts, dataIface};
1309
1310 ASSERT_TRUE(src.callouts());
1311
1312 const auto& callouts = src.callouts()->callouts();
1313
1314 // Only the first callout was successful
1315 ASSERT_EQ(callouts.size(), 1);
1316
1317 {
1318 EXPECT_EQ(callouts[0]->priority(), 'H');
1319 EXPECT_EQ(callouts[0]->locationCode(), "P0-C1");
1320
1321 auto& fru = callouts[0]->fruIdentity();
1322 EXPECT_EQ(fru->getPN().value(), "1234567");
1323 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
1324 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
1325 EXPECT_EQ(fru->failingComponentType(), src::FRUIdentity::hardwareFRU);
1326 }
1327
1328 const auto& data = src.getDebugData();
1329 ASSERT_EQ(data.size(), 4);
1330 EXPECT_STREQ(data[0].c_str(), "Unable to expand location code P0-C1: Fail");
1331 EXPECT_STREQ(data[1].c_str(),
1332 "Failed extracting callout data from JSON: Unable to "
1333 "get inventory path from location code: P0-C2: Fail");
1334 EXPECT_STREQ(data[2].c_str(),
1335 "Failed extracting callout data from JSON: "
1336 "[json.exception.out_of_range.403] key 'Priority' not found");
1337 EXPECT_STREQ(data[3].c_str(),
1338 "Failed extracting callout data from JSON: Invalid "
1339 "priority 'X' found in JSON callout");
1340}
Miguel Gomez53ef1552020-10-14 21:16:32 +00001341
1342// Test that an inventory path callout can have
1343// a different priority than H.
1344TEST_F(SRCTest, InventoryCalloutTestPriority)
1345{
1346 message::Entry entry;
1347 entry.src.type = 0xBD;
1348 entry.src.reasonCode = 0xABCD;
1349 entry.subsystem = 0x42;
Miguel Gomez53ef1552020-10-14 21:16:32 +00001350
1351 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard",
1352 "CALLOUT_PRIORITY=M"};
1353 AdditionalData ad{adData};
1354 NiceMock<MockDataInterface> dataIface;
1355
Sumit Kumar9d43a722021-08-24 09:46:19 -05001356 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1357 "system/entry"};
1358 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1359 .WillOnce(Return(std::vector<bool>{false, false, false}));
1360
Miguel Gomez53ef1552020-10-14 21:16:32 +00001361 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
1362 .WillOnce(Return("UTMS-P1"));
1363
1364 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
1365 .Times(1)
1366 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
1367 SetArgReferee<3>("123456789ABC")));
1368
1369 SRC src{entry, ad, dataIface};
1370 EXPECT_TRUE(src.valid());
1371
1372 ASSERT_TRUE(src.callouts());
1373
1374 EXPECT_EQ(src.callouts()->callouts().size(), 1);
1375
1376 auto& callout = src.callouts()->callouts().front();
1377
1378 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
1379 EXPECT_EQ(callout->priority(), 'M');
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +08001380}
Sumit Kumar9d43a722021-08-24 09:46:19 -05001381
1382// Test for bmc & platform dump status bits
1383TEST_F(SRCTest, DumpStatusBitsCheck)
1384{
1385 message::Entry entry;
1386 entry.src.type = 0xBD;
1387 entry.src.reasonCode = 0xABCD;
1388 entry.subsystem = 0x42;
Sumit Kumar9d43a722021-08-24 09:46:19 -05001389
1390 AdditionalData ad;
1391 NiceMock<MockDataInterface> dataIface;
1392 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1393 "system/entry"};
1394
1395 {
1396 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1397 .WillOnce(Return(std::vector<bool>{true, false, false}));
1398
1399 SRC src{entry, ad, dataIface};
1400 EXPECT_TRUE(src.valid());
1401
1402 const auto& hexwords = src.hexwordData();
1403 EXPECT_EQ(0x00080055, hexwords[0]);
1404 }
1405
1406 {
1407 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1408 .WillOnce(Return(std::vector<bool>{false, true, false}));
1409
1410 SRC src{entry, ad, dataIface};
1411 EXPECT_TRUE(src.valid());
1412
1413 const auto& hexwords = src.hexwordData();
1414 EXPECT_EQ(0x00000255, hexwords[0]);
1415 }
1416
1417 {
1418 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1419 .WillOnce(Return(std::vector<bool>{false, false, true}));
1420
1421 SRC src{entry, ad, dataIface};
1422 EXPECT_TRUE(src.valid());
1423
1424 const auto& hexwords = src.hexwordData();
1425 EXPECT_EQ(0x00000455, hexwords[0]);
1426 }
1427
1428 {
1429 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1430 .WillOnce(Return(std::vector<bool>{true, true, true}));
1431
1432 SRC src{entry, ad, dataIface};
1433 EXPECT_TRUE(src.valid());
1434
1435 const auto& hexwords = src.hexwordData();
1436 EXPECT_EQ(0x00080655, hexwords[0]);
1437 }
1438}
Sumit Kumar50bfa692022-01-06 06:48:26 -06001439
1440// Test SRC with additional data - PEL_SUBSYSTEM
1441TEST_F(SRCTest, TestPELSubsystem)
1442{
1443 message::Entry entry;
1444 entry.src.type = 0xBD;
1445 entry.src.reasonCode = 0xABCD;
1446 entry.subsystem = 0x42;
Sumit Kumar50bfa692022-01-06 06:48:26 -06001447
1448 // Values for the SRC words pointed to above
1449 std::vector<std::string> adData{"PEL_SUBSYSTEM=0x20"};
1450 AdditionalData ad{adData};
1451 NiceMock<MockDataInterface> dataIface;
1452
1453 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
1454
1455 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1456 "system/entry"};
1457 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1458 .WillOnce(Return(std::vector<bool>{false, false, false}));
1459
1460 SRC src{entry, ad, dataIface};
1461
1462 EXPECT_TRUE(src.valid());
1463
1464 EXPECT_EQ(src.asciiString(), "BD20ABCD ");
1465}
Vijay Lobo875b6c72021-10-20 17:38:56 -05001466
1467void setAsciiString(std::vector<uint8_t>& src, const std::string& value)
1468{
1469 assert(40 + value.size() <= src.size());
1470
1471 for (size_t i = 0; i < value.size(); i++)
1472 {
1473 src[40 + i] = value[i];
1474 }
1475}
1476
1477TEST_F(SRCTest, TestGetProgressCode)
1478{
1479 {
1480 // A real SRC with CC009184
1481 std::vector<uint8_t> src{
1482 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1483 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1484 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1485 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1486 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1487
1488 EXPECT_EQ(SRC::getProgressCode(src), 0xCC009184);
1489 }
1490
1491 {
1492 // A real SRC with STANDBY
1493 std::vector<uint8_t> src{
1494 2, 0, 0, 1, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0,
1495 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 84, 65, 78, 68,
1497 66, 89, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1498 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1499
1500 EXPECT_EQ(SRC::getProgressCode(src), 0);
1501 }
1502
1503 {
1504 // A real SRC with CC009184, but 1 byte too short
1505 std::vector<uint8_t> src{
1506 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1507 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1509 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1510 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
1511 src.resize(71);
1512 EXPECT_EQ(SRC::getProgressCode(src), 0);
1513 }
1514
1515 {
1516 // A few different ones
1517 const std::map<std::string, uint32_t> progressCodes{
1518 {"12345678", 0x12345678}, {"ABCDEF00", 0xABCDEF00},
1519 {"abcdef00", 0xABCDEF00}, {"X1234567", 0},
1520 {"1234567X", 0}, {"1 ", 0}};
1521
1522 std::vector<uint8_t> src(72, 0x0);
1523
1524 for (const auto& [code, expected] : progressCodes)
1525 {
1526 setAsciiString(src, code);
1527 EXPECT_EQ(SRC::getProgressCode(src), expected);
1528 }
1529
1530 // empty
1531 src.clear();
1532 EXPECT_EQ(SRC::getProgressCode(src), 0);
1533 }
1534}
1535
1536// Test progress is in right SRC hex data field
1537TEST_F(SRCTest, TestProgressCodeField)
1538{
1539 message::Entry entry;
1540 entry.src.type = 0xBD;
1541 entry.src.reasonCode = 0xABCD;
1542 entry.subsystem = 0x42;
1543
1544 AdditionalData ad;
1545 NiceMock<MockDataInterface> dataIface;
1546 std::vector<std::string> dumpType{"bmc/entry", "resource/entry",
1547 "system/entry"};
1548 EXPECT_CALL(dataIface, checkDumpStatus(dumpType))
1549 .WillOnce(Return(std::vector<bool>{false, false, false}));
1550 EXPECT_CALL(dataIface, getRawProgressSRC())
1551 .WillOnce(Return(std::vector<uint8_t>{
1552 2, 8, 0, 9, 0, 0, 0, 72, 0, 0, 0, 224, 0, 0, 0,
1553 0, 204, 0, 145, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 48, 48, 57,
1555 49, 56, 52, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1556 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}));
1557
1558 SRC src{entry, ad, dataIface};
1559 EXPECT_TRUE(src.valid());
1560
1561 // Verify that the hex vlue is set at the right hexword
1562 EXPECT_EQ(src.hexwordData()[2], 0xCC009184);
1563}