blob: e9abb8e1e39ac4f8c9527f6108aef104deaf445e [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::_;
26using ::testing::InvokeWithoutArgs;
Matt Spinler075e5ba2020-02-21 15:46:00 -060027using ::testing::NiceMock;
28using ::testing::Return;
Matt Spinlered046852020-03-13 13:58:15 -050029using ::testing::SetArgReferee;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080030namespace fs = std::filesystem;
Matt Spinlerf9bae182019-10-09 13:37:38 -050031
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +080032const auto testRegistry = R"(
33{
34"PELs":
35[
36 {
37 "Name": "xyz.openbmc_project.Error.Test",
38 "Subsystem": "bmc_firmware",
39 "SRC":
40 {
41 "ReasonCode": "0xABCD",
42 "Words6To9":
43 {
44 "6":
45 {
46 "Description": "Component ID",
47 "AdditionalDataPropSource": "COMPID"
48 },
49 "7":
50 {
51 "Description": "Failure count",
52 "AdditionalDataPropSource": "FREQUENCY"
53 },
54 "8":
55 {
56 "Description": "Time period",
57 "AdditionalDataPropSource": "DURATION"
58 },
59 "9":
60 {
61 "Description": "Error code",
62 "AdditionalDataPropSource": "ERRORCODE"
63 }
64 }
65 },
66 "Documentation":
67 {
68 "Description": "A Component Fault",
69 "Message": "Comp %1 failed %2 times over %3 secs with ErrorCode %4",
70 "MessageArgSources":
71 [
72 "SRCWord6", "SRCWord7", "SRCWord8", "SRCWord9"
73 ]
74 }
75 }
76]
77}
78)";
79
80class SRCTest : public ::testing::Test
81{
82 protected:
83 static void SetUpTestCase()
84 {
85 char path[] = "/tmp/srctestXXXXXX";
86 regDir = mkdtemp(path);
87 }
88
89 static void TearDownTestCase()
90 {
91 fs::remove_all(regDir);
92 }
93
94 static std::string writeData(const char* data)
95 {
96 fs::path path = regDir / "registry.json";
97 std::ofstream stream{path};
98 stream << data;
99 return path;
100 }
101
102 static fs::path regDir;
103};
104
105fs::path SRCTest::regDir{};
106
107TEST_F(SRCTest, UnflattenFlattenTestNoCallouts)
Matt Spinlerf9bae182019-10-09 13:37:38 -0500108{
Matt Spinler42828bd2019-10-11 10:39:30 -0500109 auto data = pelDataFactory(TestPELType::primarySRCSection);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500110
111 Stream stream{data};
112 SRC src{stream};
113
114 EXPECT_TRUE(src.valid());
115
116 EXPECT_EQ(src.header().id, 0x5053);
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600117 EXPECT_EQ(src.header().size, 0x50);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500118 EXPECT_EQ(src.header().version, 0x01);
119 EXPECT_EQ(src.header().subType, 0x01);
120 EXPECT_EQ(src.header().componentID, 0x0202);
121
122 EXPECT_EQ(src.version(), 0x02);
123 EXPECT_EQ(src.flags(), 0x00);
124 EXPECT_EQ(src.hexWordCount(), 9);
125 EXPECT_EQ(src.size(), 0x48);
126
127 const auto& hexwords = src.hexwordData();
Matt Spinlerbd716f02019-10-15 10:54:11 -0500128 EXPECT_EQ(0x02020255, hexwords[0]);
129 EXPECT_EQ(0x03030310, hexwords[1]);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500130 EXPECT_EQ(0x04040404, hexwords[2]);
131 EXPECT_EQ(0x05050505, hexwords[3]);
132 EXPECT_EQ(0x06060606, hexwords[4]);
133 EXPECT_EQ(0x07070707, hexwords[5]);
134 EXPECT_EQ(0x08080808, hexwords[6]);
135 EXPECT_EQ(0x09090909, hexwords[7]);
136
137 EXPECT_EQ(src.asciiString(), "BD8D5678 ");
138 EXPECT_FALSE(src.callouts());
139
140 // Flatten
141 std::vector<uint8_t> newData;
142 Stream newStream{newData};
143
144 src.flatten(newStream);
145 EXPECT_EQ(data, newData);
146}
147
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800148TEST_F(SRCTest, UnflattenFlattenTest2Callouts)
Matt Spinlerf9bae182019-10-09 13:37:38 -0500149{
Matt Spinler42828bd2019-10-11 10:39:30 -0500150 auto data = pelDataFactory(TestPELType::primarySRCSection2Callouts);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500151
152 Stream stream{data};
153 SRC src{stream};
154
155 EXPECT_TRUE(src.valid());
Matt Spinlerbd716f02019-10-15 10:54:11 -0500156 EXPECT_EQ(src.flags(), 0x01); // Additional sections within the SRC.
Matt Spinlerf9bae182019-10-09 13:37:38 -0500157
158 // Spot check the SRC fields, but they're the same as above
159 EXPECT_EQ(src.asciiString(), "BD8D5678 ");
160
161 // There should be 2 callouts
162 const auto& calloutsSection = src.callouts();
163 ASSERT_TRUE(calloutsSection);
164 const auto& callouts = calloutsSection->callouts();
165 EXPECT_EQ(callouts.size(), 2);
166
167 // spot check that each callout has the right substructures
168 EXPECT_TRUE(callouts.front()->fruIdentity());
169 EXPECT_FALSE(callouts.front()->pceIdentity());
170 EXPECT_FALSE(callouts.front()->mru());
171
172 EXPECT_TRUE(callouts.back()->fruIdentity());
173 EXPECT_TRUE(callouts.back()->pceIdentity());
174 EXPECT_TRUE(callouts.back()->mru());
175
176 // Flatten
177 std::vector<uint8_t> newData;
178 Stream newStream{newData};
179
180 src.flatten(newStream);
181 EXPECT_EQ(data, newData);
182}
Matt Spinlerbd716f02019-10-15 10:54:11 -0500183
184// Create an SRC from the message registry
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800185TEST_F(SRCTest, CreateTestNoCallouts)
Matt Spinlerbd716f02019-10-15 10:54:11 -0500186{
187 message::Entry entry;
188 entry.src.type = 0xBD;
189 entry.src.reasonCode = 0xABCD;
190 entry.subsystem = 0x42;
191 entry.src.powerFault = true;
192 entry.src.hexwordADFields = {{5, "TEST1"}, // Not a user defined word
193 {6, "TEST1"},
194 {7, "TEST2"},
195 {8, "TEST3"},
196 {9, "TEST4"}};
197
198 // Values for the SRC words pointed to above
199 std::vector<std::string> adData{"TEST1=0x12345678", "TEST2=12345678",
200 "TEST3=0XDEF", "TEST4=Z"};
201 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600202 NiceMock<MockDataInterface> dataIface;
203
204 EXPECT_CALL(dataIface, getMotherboardCCIN).WillOnce(Return("ABCD"));
205
206 SRC src{entry, ad, dataIface};
Matt Spinlerbd716f02019-10-15 10:54:11 -0500207
208 EXPECT_TRUE(src.valid());
209 EXPECT_TRUE(src.isPowerFaultEvent());
210 EXPECT_EQ(src.size(), baseSRCSize);
211
212 const auto& hexwords = src.hexwordData();
213
214 // The spec always refers to SRC words 2 - 9, and as the hexwordData()
215 // array index starts at 0 use the math in the [] below to make it easier
216 // to tell what is being accessed.
217 EXPECT_EQ(hexwords[2 - 2] & 0xF0000000, 0); // Partition dump status
218 EXPECT_EQ(hexwords[2 - 2] & 0x00F00000, 0); // Partition boot type
219 EXPECT_EQ(hexwords[2 - 2] & 0x000000FF, 0x55); // SRC format
220 EXPECT_EQ(hexwords[3 - 2] & 0x000000FF, 0x10); // BMC position
Matt Spinler075e5ba2020-02-21 15:46:00 -0600221 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0xABCD0000); // Motherboard CCIN
Matt Spinlerbd716f02019-10-15 10:54:11 -0500222
223 // Validate more fields here as the code starts filling them in.
224
225 // Ensure hex word 5 wasn't allowed to be set to TEST1's contents
226 EXPECT_EQ(hexwords[5 - 2], 0);
227
228 // The user defined hex word fields specifed in the additional data.
229 EXPECT_EQ(hexwords[6 - 2], 0x12345678); // TEST1
230 EXPECT_EQ(hexwords[7 - 2], 12345678); // TEST2
231 EXPECT_EQ(hexwords[8 - 2], 0xdef); // TEST3
232 EXPECT_EQ(hexwords[9 - 2], 0); // TEST4, but can't convert a 'Z'
233
234 EXPECT_EQ(src.asciiString(), "BD42ABCD ");
235
236 // No callouts
237 EXPECT_FALSE(src.callouts());
238
239 // May as well spot check the flatten/unflatten
240 std::vector<uint8_t> data;
241 Stream stream{data};
242 src.flatten(stream);
243
244 stream.offset(0);
245 SRC newSRC{stream};
246
247 EXPECT_TRUE(newSRC.valid());
248 EXPECT_EQ(newSRC.isPowerFaultEvent(), src.isPowerFaultEvent());
249 EXPECT_EQ(newSRC.asciiString(), src.asciiString());
250 EXPECT_FALSE(newSRC.callouts());
251}
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800252
Matt Spinler075e5ba2020-02-21 15:46:00 -0600253// Test when the CCIN string isn't a 4 character number
254TEST_F(SRCTest, BadCCINTest)
255{
256 message::Entry entry;
257 entry.src.type = 0xBD;
258 entry.src.reasonCode = 0xABCD;
259 entry.subsystem = 0x42;
260 entry.src.powerFault = false;
261
262 std::vector<std::string> adData{};
263 AdditionalData ad{adData};
264 NiceMock<MockDataInterface> dataIface;
265
266 // First it isn't a number, then it is too long,
267 // then it is empty.
268 EXPECT_CALL(dataIface, getMotherboardCCIN)
269 .WillOnce(Return("X"))
270 .WillOnce(Return("12345"))
271 .WillOnce(Return(""));
272
273 // The CCIN in the first half should still be 0 each time.
274 {
275 SRC src{entry, ad, dataIface};
276 EXPECT_TRUE(src.valid());
277 const auto& hexwords = src.hexwordData();
278 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
279 }
280
281 {
282 SRC src{entry, ad, dataIface};
283 EXPECT_TRUE(src.valid());
284 const auto& hexwords = src.hexwordData();
285 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
286 }
287
288 {
289 SRC src{entry, ad, dataIface};
290 EXPECT_TRUE(src.valid());
291 const auto& hexwords = src.hexwordData();
292 EXPECT_EQ(hexwords[3 - 2] & 0xFFFF0000, 0x00000000);
293 }
294}
295
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800296// Test the getErrorDetails function
297TEST_F(SRCTest, MessageSubstitutionTest)
298{
299 auto path = SRCTest::writeData(testRegistry);
300 message::Registry registry{path};
301 auto entry = registry.lookup("0xABCD", message::LookupType::reasonCode);
302
303 std::vector<std::string> adData{"COMPID=0x1", "FREQUENCY=0x4",
304 "DURATION=30", "ERRORCODE=0x01ABCDEF"};
305 AdditionalData ad{adData};
Matt Spinler075e5ba2020-02-21 15:46:00 -0600306 NiceMock<MockDataInterface> dataIface;
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800307
Matt Spinler075e5ba2020-02-21 15:46:00 -0600308 SRC src{*entry, ad, dataIface};
Harisuddin Mohamed Isa6fd0c1e2020-02-06 14:25:57 +0800309 EXPECT_TRUE(src.valid());
310
311 auto errorDetails = src.getErrorDetails(registry, DetailLevel::message);
312 ASSERT_TRUE(errorDetails);
313 EXPECT_EQ(
314 errorDetails.value(),
315 "Comp 0x1 failed 0x4 times over 0x1E secs with ErrorCode 0x1ABCDEF");
316}
Matt Spinlered046852020-03-13 13:58:15 -0500317
318// Test that an inventory path callout string is
319// converted into the appropriate FRU callout.
320TEST_F(SRCTest, InventoryCalloutTest)
321{
322 message::Entry entry;
323 entry.src.type = 0xBD;
324 entry.src.reasonCode = 0xABCD;
325 entry.subsystem = 0x42;
326 entry.src.powerFault = false;
327
328 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
329 AdditionalData ad{adData};
330 NiceMock<MockDataInterface> dataIface;
331
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500332 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
333 .WillOnce(Return("UTMS-P1"));
334
335 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500336 .Times(1)
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500337 .WillOnce(DoAll(SetArgReferee<1>("1234567"), SetArgReferee<2>("CCCC"),
338 SetArgReferee<3>("123456789ABC")));
Matt Spinlered046852020-03-13 13:58:15 -0500339
340 SRC src{entry, ad, dataIface};
341 EXPECT_TRUE(src.valid());
342
343 ASSERT_TRUE(src.callouts());
344
345 EXPECT_EQ(src.callouts()->callouts().size(), 1);
346
347 auto& callout = src.callouts()->callouts().front();
348
349 EXPECT_EQ(callout->locationCode(), "UTMS-P1");
350
351 auto& fru = callout->fruIdentity();
352
353 EXPECT_EQ(fru->getPN().value(), "1234567");
354 EXPECT_EQ(fru->getCCIN().value(), "CCCC");
355 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
356
357 // flatten and unflatten
358 std::vector<uint8_t> data;
359 Stream stream{data};
360 src.flatten(stream);
361
362 stream.offset(0);
363 SRC newSRC{stream};
364 EXPECT_TRUE(newSRC.valid());
365 ASSERT_TRUE(src.callouts());
366 EXPECT_EQ(src.callouts()->callouts().size(), 1);
367}
368
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500369// Test that when the location code can't be obtained that
Matt Spinlered046852020-03-13 13:58:15 -0500370// a procedure callout is used.
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500371TEST_F(SRCTest, InventoryCalloutNoLocCodeTest)
372{
373 message::Entry entry;
374 entry.src.type = 0xBD;
375 entry.src.reasonCode = 0xABCD;
376 entry.subsystem = 0x42;
377 entry.src.powerFault = false;
378
379 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
380 AdditionalData ad{adData};
381 NiceMock<MockDataInterface> dataIface;
382
383 auto func = []() {
384 throw sdbusplus::exception::SdBusError(5, "Error");
385 return std::string{};
386 };
387
388 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
389 .Times(1)
390 .WillOnce(InvokeWithoutArgs(func));
391
392 EXPECT_CALL(dataIface, getHWCalloutFields(_, _, _, _)).Times(0);
393
394 SRC src{entry, ad, dataIface};
395 EXPECT_TRUE(src.valid());
396
397 ASSERT_TRUE(src.callouts());
398
399 EXPECT_EQ(src.callouts()->callouts().size(), 1);
400
401 auto& callout = src.callouts()->callouts().front();
402 EXPECT_EQ(callout->locationCodeSize(), 0);
403
404 auto& fru = callout->fruIdentity();
405
406 EXPECT_EQ(fru->getMaintProc().value(), "BMCSP01");
407 EXPECT_FALSE(fru->getPN());
408 EXPECT_FALSE(fru->getSN());
409 EXPECT_FALSE(fru->getCCIN());
410
411 // flatten and unflatten
412 std::vector<uint8_t> data;
413 Stream stream{data};
414 src.flatten(stream);
415
416 stream.offset(0);
417 SRC newSRC{stream};
418 EXPECT_TRUE(newSRC.valid());
419 ASSERT_TRUE(src.callouts());
420 EXPECT_EQ(src.callouts()->callouts().size(), 1);
421}
422
423// Test that when the VPD can't be obtained that
424// a callout is still created.
Matt Spinlered046852020-03-13 13:58:15 -0500425TEST_F(SRCTest, InventoryCalloutNoVPDTest)
426{
427 message::Entry entry;
428 entry.src.type = 0xBD;
429 entry.src.reasonCode = 0xABCD;
430 entry.subsystem = 0x42;
431 entry.src.powerFault = false;
432
433 std::vector<std::string> adData{"CALLOUT_INVENTORY_PATH=motherboard"};
434 AdditionalData ad{adData};
435 NiceMock<MockDataInterface> dataIface;
436
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500437 EXPECT_CALL(dataIface, getLocationCode("motherboard"))
438 .Times(1)
439 .WillOnce(Return("UTMS-P10"));
440
Matt Spinlered046852020-03-13 13:58:15 -0500441 auto func = []() { throw sdbusplus::exception::SdBusError(5, "Error"); };
442
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500443 EXPECT_CALL(dataIface, getHWCalloutFields("motherboard", _, _, _))
Matt Spinlered046852020-03-13 13:58:15 -0500444 .Times(1)
445 .WillOnce(InvokeWithoutArgs(func));
446
447 SRC src{entry, ad, dataIface};
448 EXPECT_TRUE(src.valid());
Matt Spinlered046852020-03-13 13:58:15 -0500449 ASSERT_TRUE(src.callouts());
Matt Spinlered046852020-03-13 13:58:15 -0500450 EXPECT_EQ(src.callouts()->callouts().size(), 1);
451
452 auto& callout = src.callouts()->callouts().front();
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500453 EXPECT_EQ(callout->locationCode(), "UTMS-P10");
Matt Spinlered046852020-03-13 13:58:15 -0500454
455 auto& fru = callout->fruIdentity();
456
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500457 EXPECT_EQ(fru->getPN(), "");
458 EXPECT_EQ(fru->getCCIN(), "");
459 EXPECT_EQ(fru->getSN(), "");
460 EXPECT_FALSE(fru->getMaintProc());
461
Matt Spinlered046852020-03-13 13:58:15 -0500462 // flatten and unflatten
463 std::vector<uint8_t> data;
464 Stream stream{data};
465 src.flatten(stream);
466
467 stream.offset(0);
468 SRC newSRC{stream};
469 EXPECT_TRUE(newSRC.valid());
470 ASSERT_TRUE(src.callouts());
471 EXPECT_EQ(src.callouts()->callouts().size(), 1);
472}
Matt Spinler03984582020-04-09 13:17:58 -0500473
474TEST_F(SRCTest, RegistryCalloutTest)
475{
476 message::Entry entry;
477 entry.src.type = 0xBD;
478 entry.src.reasonCode = 0xABCD;
479 entry.subsystem = 0x42;
480 entry.src.powerFault = false;
481
482 entry.callouts = R"(
483 [
484 {
485 "System": "systemA",
486 "CalloutList":
487 [
488 {
489 "Priority": "high",
490 "SymbolicFRU": "service_docs"
491 },
492 {
493 "Priority": "medium",
494 "Procedure": "no_vpd_for_fru"
495 }
496 ]
497 },
498 {
499 "System": "systemB",
500 "CalloutList":
501 [
502 {
503 "Priority": "high",
504 "LocCode": "P0-C8",
505 "SymbolicFRUTrusted": "service_docs"
506 },
507 {
508 "Priority": "medium",
509 "SymbolicFRUTrusted": "service_docs"
510 }
511 ]
512
513 }
514 ])"_json;
515
516 {
517 // Call out a symbolic FRU and a procedure
518 AdditionalData ad;
519 NiceMock<MockDataInterface> dataIface;
520 EXPECT_CALL(dataIface, getSystemType).WillOnce(Return("systemA"));
521
522 SRC src{entry, ad, dataIface};
523
524 auto& callouts = src.callouts()->callouts();
525 ASSERT_EQ(callouts.size(), 2);
526
527 EXPECT_EQ(callouts[0]->locationCodeSize(), 0);
528 EXPECT_EQ(callouts[0]->priority(), 'H');
529
530 EXPECT_EQ(callouts[1]->locationCodeSize(), 0);
531 EXPECT_EQ(callouts[1]->priority(), 'M');
532
533 auto& fru1 = callouts[0]->fruIdentity();
534 EXPECT_EQ(fru1->getPN().value(), "SVCDOCS");
535 EXPECT_EQ(fru1->failingComponentType(), src::FRUIdentity::symbolicFRU);
536 EXPECT_FALSE(fru1->getMaintProc());
537 EXPECT_FALSE(fru1->getSN());
538 EXPECT_FALSE(fru1->getCCIN());
539
540 auto& fru2 = callouts[1]->fruIdentity();
541 EXPECT_EQ(fru2->getMaintProc().value(), "BMCSP01");
542 EXPECT_EQ(fru2->failingComponentType(),
543 src::FRUIdentity::maintenanceProc);
544 EXPECT_FALSE(fru2->getPN());
545 EXPECT_FALSE(fru2->getSN());
546 EXPECT_FALSE(fru2->getCCIN());
547 }
548
549 {
550 // Call out a trusted symbolic FRU with a location code, and
551 // another one without.
552 AdditionalData ad;
553 NiceMock<MockDataInterface> dataIface;
554 EXPECT_CALL(dataIface, getSystemType).WillOnce(Return("systemB"));
555
556 SRC src{entry, ad, dataIface};
557
558 auto& callouts = src.callouts()->callouts();
559 EXPECT_EQ(callouts.size(), 2);
560
561 EXPECT_EQ(callouts[0]->locationCode(), "P0-C8");
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(),
570 src::FRUIdentity::symbolicFRUTrustedLocCode);
571 EXPECT_FALSE(fru1->getMaintProc());
572 EXPECT_FALSE(fru1->getSN());
573 EXPECT_FALSE(fru1->getCCIN());
574
575 // It asked for a trusted symbolic FRU, but no location code
576 // was provided so it is switched back to a normal one
577 auto& fru2 = callouts[1]->fruIdentity();
578 EXPECT_EQ(fru2->getPN().value(), "SVCDOCS");
579 EXPECT_EQ(fru2->failingComponentType(), src::FRUIdentity::symbolicFRU);
580 EXPECT_FALSE(fru2->getMaintProc());
581 EXPECT_FALSE(fru2->getSN());
582 EXPECT_FALSE(fru2->getCCIN());
583 }
584}