1 /**
2 * Copyright © 2024 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 */
16
17 #include "mock_device.hpp"
18 #include "mock_services.hpp"
19 #include "rail.hpp"
20
21 #include <cstdint>
22 #include <map>
23 #include <optional>
24 #include <string>
25 #include <vector>
26
27 #include <gmock/gmock.h>
28 #include <gtest/gtest.h>
29
30 using namespace phosphor::power::sequencer;
31
32 using ::testing::Return;
33 using ::testing::Throw;
34
TEST(GPIOTests,Initialization)35 TEST(GPIOTests, Initialization)
36 {
37 // Default initialization
38 {
39 GPIO gpio;
40 EXPECT_EQ(gpio.line, 0);
41 EXPECT_FALSE(gpio.activeLow);
42 }
43
44 // Explicit initialization
45 {
46 GPIO gpio{48, true};
47 EXPECT_EQ(gpio.line, 48);
48 EXPECT_TRUE(gpio.activeLow);
49 }
50 }
51
TEST(RailTests,Constructor)52 TEST(RailTests, Constructor)
53 {
54 // Test where succeeds: No optional parameters have values
55 {
56 std::string name{"12.0V"};
57 std::optional<std::string> presence{};
58 std::optional<uint8_t> page{};
59 bool isPowerSupplyRail{true};
60 bool checkStatusVout{false};
61 bool compareVoltageToLimit{false};
62 std::optional<GPIO> gpio{};
63 Rail rail{name,
64 presence,
65 page,
66 isPowerSupplyRail,
67 checkStatusVout,
68 compareVoltageToLimit,
69 gpio};
70
71 EXPECT_EQ(rail.getName(), "12.0V");
72 EXPECT_FALSE(rail.getPresence().has_value());
73 EXPECT_FALSE(rail.getPage().has_value());
74 EXPECT_TRUE(rail.isPowerSupplyRail());
75 EXPECT_FALSE(rail.getCheckStatusVout());
76 EXPECT_FALSE(rail.getCompareVoltageToLimit());
77 EXPECT_FALSE(rail.getGPIO().has_value());
78 }
79
80 // Test where succeeds: All optional parameters have values
81 {
82 std::string name{"VCS_CPU1"};
83 std::optional<std::string> presence{
84 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1"};
85 std::optional<uint8_t> page{11};
86 bool isPowerSupplyRail{false};
87 bool checkStatusVout{true};
88 bool compareVoltageToLimit{true};
89 std::optional<GPIO> gpio{GPIO(60, true)};
90 Rail rail{name,
91 presence,
92 page,
93 isPowerSupplyRail,
94 checkStatusVout,
95 compareVoltageToLimit,
96 gpio};
97
98 EXPECT_EQ(rail.getName(), "VCS_CPU1");
99 EXPECT_TRUE(rail.getPresence().has_value());
100 EXPECT_EQ(
101 rail.getPresence().value(),
102 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1");
103 EXPECT_TRUE(rail.getPage().has_value());
104 EXPECT_EQ(rail.getPage().value(), 11);
105 EXPECT_FALSE(rail.isPowerSupplyRail());
106 EXPECT_TRUE(rail.getCheckStatusVout());
107 EXPECT_TRUE(rail.getCompareVoltageToLimit());
108 EXPECT_TRUE(rail.getGPIO().has_value());
109 EXPECT_EQ(rail.getGPIO().value().line, 60);
110 EXPECT_TRUE(rail.getGPIO().value().activeLow);
111 }
112
113 // Test where fails: checkStatusVout is true and page has no value
114 {
115 std::string name{"VDD1"};
116 std::optional<std::string> presence{};
117 std::optional<uint8_t> page{};
118 bool isPowerSupplyRail{false};
119 bool checkStatusVout{true};
120 bool compareVoltageToLimit{false};
121 std::optional<GPIO> gpio{};
122 EXPECT_THROW((Rail{name, presence, page, isPowerSupplyRail,
123 checkStatusVout, compareVoltageToLimit, gpio}),
124 std::invalid_argument);
125 }
126
127 // Test where fails: compareVoltageToLimit is true and page has no value
128 {
129 std::string name{"VDD1"};
130 std::optional<std::string> presence{};
131 std::optional<uint8_t> page{};
132 bool isPowerSupplyRail{false};
133 bool checkStatusVout{false};
134 bool compareVoltageToLimit{true};
135 std::optional<GPIO> gpio{};
136 EXPECT_THROW((Rail{name, presence, page, isPowerSupplyRail,
137 checkStatusVout, compareVoltageToLimit, gpio}),
138 std::invalid_argument);
139 }
140 }
141
TEST(RailTests,GetName)142 TEST(RailTests, GetName)
143 {
144 std::string name{"VDD2"};
145 std::optional<std::string> presence{};
146 std::optional<uint8_t> page{};
147 bool isPowerSupplyRail{false};
148 bool checkStatusVout{false};
149 bool compareVoltageToLimit{false};
150 std::optional<GPIO> gpio{};
151 Rail rail{name,
152 presence,
153 page,
154 isPowerSupplyRail,
155 checkStatusVout,
156 compareVoltageToLimit,
157 gpio};
158
159 EXPECT_EQ(rail.getName(), "VDD2");
160 }
161
TEST(RailTests,GetPresence)162 TEST(RailTests, GetPresence)
163 {
164 std::string name{"VDDR2"};
165 std::optional<uint8_t> page{};
166 bool isPowerSupplyRail{false};
167 bool checkStatusVout{false};
168 bool compareVoltageToLimit{false};
169 std::optional<GPIO> gpio{};
170
171 // Test where presence has no value
172 {
173 std::optional<std::string> presence{};
174 Rail rail{name,
175 presence,
176 page,
177 isPowerSupplyRail,
178 checkStatusVout,
179 compareVoltageToLimit,
180 gpio};
181 EXPECT_FALSE(rail.getPresence().has_value());
182 }
183
184 // Test where presence has a value
185 {
186 std::optional<std::string> presence{
187 "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm2"};
188 Rail rail{name,
189 presence,
190 page,
191 isPowerSupplyRail,
192 checkStatusVout,
193 compareVoltageToLimit,
194 gpio};
195 EXPECT_TRUE(rail.getPresence().has_value());
196 EXPECT_EQ(
197 rail.getPresence().value(),
198 "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm2");
199 }
200 }
201
TEST(RailTests,GetPage)202 TEST(RailTests, GetPage)
203 {
204 std::string name{"VDD2"};
205 std::optional<std::string> presence{};
206 bool isPowerSupplyRail{false};
207 bool checkStatusVout{false};
208 bool compareVoltageToLimit{false};
209 std::optional<GPIO> gpio{};
210
211 // Test where page has no value
212 {
213 std::optional<uint8_t> page{};
214 Rail rail{name,
215 presence,
216 page,
217 isPowerSupplyRail,
218 checkStatusVout,
219 compareVoltageToLimit,
220 gpio};
221 EXPECT_FALSE(rail.getPage().has_value());
222 }
223
224 // Test where page has a value
225 {
226 std::optional<uint8_t> page{7};
227 Rail rail{name,
228 presence,
229 page,
230 isPowerSupplyRail,
231 checkStatusVout,
232 compareVoltageToLimit,
233 gpio};
234 EXPECT_TRUE(rail.getPage().has_value());
235 EXPECT_EQ(rail.getPage().value(), 7);
236 }
237 }
238
TEST(RailTests,IsPowerSupplyRail)239 TEST(RailTests, IsPowerSupplyRail)
240 {
241 std::string name{"12.0V"};
242 std::optional<std::string> presence{};
243 std::optional<uint8_t> page{};
244 bool isPowerSupplyRail{true};
245 bool checkStatusVout{false};
246 bool compareVoltageToLimit{false};
247 std::optional<GPIO> gpio{};
248 Rail rail{name,
249 presence,
250 page,
251 isPowerSupplyRail,
252 checkStatusVout,
253 compareVoltageToLimit,
254 gpio};
255
256 EXPECT_TRUE(rail.isPowerSupplyRail());
257 }
258
TEST(RailTests,GetCheckStatusVout)259 TEST(RailTests, GetCheckStatusVout)
260 {
261 std::string name{"VDD2"};
262 std::optional<std::string> presence{};
263 std::optional<uint8_t> page{};
264 bool isPowerSupplyRail{false};
265 bool checkStatusVout{false};
266 bool compareVoltageToLimit{false};
267 std::optional<GPIO> gpio{};
268 Rail rail{name,
269 presence,
270 page,
271 isPowerSupplyRail,
272 checkStatusVout,
273 compareVoltageToLimit,
274 gpio};
275
276 EXPECT_FALSE(rail.getCheckStatusVout());
277 }
278
TEST(RailTests,GetCompareVoltageToLimit)279 TEST(RailTests, GetCompareVoltageToLimit)
280 {
281 std::string name{"VDD2"};
282 std::optional<std::string> presence{};
283 std::optional<uint8_t> page{13};
284 bool isPowerSupplyRail{false};
285 bool checkStatusVout{false};
286 bool compareVoltageToLimit{true};
287 std::optional<GPIO> gpio{};
288 Rail rail{name,
289 presence,
290 page,
291 isPowerSupplyRail,
292 checkStatusVout,
293 compareVoltageToLimit,
294 gpio};
295
296 EXPECT_TRUE(rail.getCompareVoltageToLimit());
297 }
298
TEST(RailTests,GetGPIO)299 TEST(RailTests, GetGPIO)
300 {
301 std::string name{"VDD2"};
302 std::optional<std::string> presence{};
303 std::optional<uint8_t> page{};
304 bool isPowerSupplyRail{false};
305 bool checkStatusVout{false};
306 bool compareVoltageToLimit{false};
307
308 // Test where gpio has no value
309 {
310 std::optional<GPIO> gpio{};
311 Rail rail{name,
312 presence,
313 page,
314 isPowerSupplyRail,
315 checkStatusVout,
316 compareVoltageToLimit,
317 gpio};
318 EXPECT_FALSE(rail.getGPIO().has_value());
319 }
320
321 // Test where gpio has a value
322 {
323 std::optional<GPIO> gpio{GPIO(12, false)};
324 Rail rail{name,
325 presence,
326 page,
327 isPowerSupplyRail,
328 checkStatusVout,
329 compareVoltageToLimit,
330 gpio};
331 EXPECT_TRUE(rail.getGPIO().has_value());
332 EXPECT_EQ(rail.getGPIO().value().line, 12);
333 EXPECT_FALSE(rail.getGPIO().value().activeLow);
334 }
335 }
336
TEST(RailTests,IsPresent)337 TEST(RailTests, IsPresent)
338 {
339 std::string name{"VDD2"};
340 std::optional<uint8_t> page{};
341 bool isPowerSupplyRail{false};
342 bool checkStatusVout{false};
343 bool compareVoltageToLimit{false};
344 std::optional<GPIO> gpio{};
345
346 // Test where inventory path not specified; always returns true
347 {
348 std::optional<std::string> presence{};
349 Rail rail{name,
350 presence,
351 page,
352 isPowerSupplyRail,
353 checkStatusVout,
354 compareVoltageToLimit,
355 gpio};
356
357 MockServices services{};
358 EXPECT_CALL(services, isPresent).Times(0);
359
360 EXPECT_TRUE(rail.isPresent(services));
361 }
362
363 // Test where inventory path is not present
364 {
365 std::optional<std::string> presence{
366 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
367 Rail rail{name,
368 presence,
369 page,
370 isPowerSupplyRail,
371 checkStatusVout,
372 compareVoltageToLimit,
373 gpio};
374
375 MockServices services{};
376 EXPECT_CALL(services, isPresent(*presence))
377 .Times(1)
378 .WillOnce(Return(false));
379
380 EXPECT_FALSE(rail.isPresent(services));
381 }
382
383 // Test where inventory path is present
384 {
385 std::optional<std::string> presence{
386 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
387 Rail rail{name,
388 presence,
389 page,
390 isPowerSupplyRail,
391 checkStatusVout,
392 compareVoltageToLimit,
393 gpio};
394
395 MockServices services{};
396 EXPECT_CALL(services, isPresent(*presence))
397 .Times(1)
398 .WillOnce(Return(true));
399
400 EXPECT_TRUE(rail.isPresent(services));
401 }
402
403 // Test where exception occurs trying to get presence
404 {
405 std::optional<std::string> presence{
406 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
407 Rail rail{name,
408 presence,
409 page,
410 isPowerSupplyRail,
411 checkStatusVout,
412 compareVoltageToLimit,
413 gpio};
414
415 MockServices services{};
416 EXPECT_CALL(services, isPresent(*presence))
417 .Times(1)
418 .WillOnce(Throw(std::runtime_error{"Invalid object path"}));
419
420 try
421 {
422 rail.isPresent(services);
423 ADD_FAILURE() << "Should not have reached this line.";
424 }
425 catch (const std::exception& e)
426 {
427 EXPECT_STREQ(
428 e.what(),
429 "Unable to determine presence of rail VDD2 using "
430 "inventory path "
431 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2: "
432 "Invalid object path");
433 }
434 }
435 }
436
TEST(RailTests,GetStatusWord)437 TEST(RailTests, GetStatusWord)
438 {
439 std::string name{"VDD2"};
440 std::optional<std::string> presence{};
441 bool isPowerSupplyRail{false};
442 bool checkStatusVout{false};
443 bool compareVoltageToLimit{false};
444 std::optional<GPIO> gpio{};
445
446 // Test where page was not specified: Throws exception
447 {
448 std::optional<uint8_t> page{};
449 Rail rail{name,
450 presence,
451 page,
452 isPowerSupplyRail,
453 checkStatusVout,
454 compareVoltageToLimit,
455 gpio};
456
457 MockDevice device{};
458 EXPECT_CALL(device, getStatusWord).Times(0);
459
460 try
461 {
462 rail.getStatusWord(device);
463 ADD_FAILURE() << "Should not have reached this line.";
464 }
465 catch (const std::exception& e)
466 {
467 EXPECT_STREQ(e.what(),
468 "Unable to read STATUS_WORD value for rail VDD2: "
469 "No PAGE number defined for rail VDD2");
470 }
471 }
472
473 // Test where value read successfully
474 {
475 std::optional<uint8_t> page{2};
476 Rail rail{name,
477 presence,
478 page,
479 isPowerSupplyRail,
480 checkStatusVout,
481 compareVoltageToLimit,
482 gpio};
483
484 MockDevice device{};
485 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef));
486
487 EXPECT_EQ(rail.getStatusWord(device), 0xbeef);
488 }
489
490 // Test where exception occurs trying to read value
491 {
492 std::optional<uint8_t> page{2};
493 Rail rail{name,
494 presence,
495 page,
496 isPowerSupplyRail,
497 checkStatusVout,
498 compareVoltageToLimit,
499 gpio};
500
501 MockDevice device{};
502 EXPECT_CALL(device, getStatusWord(2))
503 .Times(1)
504 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
505
506 try
507 {
508 rail.getStatusWord(device);
509 ADD_FAILURE() << "Should not have reached this line.";
510 }
511 catch (const std::exception& e)
512 {
513 EXPECT_STREQ(e.what(),
514 "Unable to read STATUS_WORD value for rail VDD2: "
515 "File does not exist");
516 }
517 }
518 }
519
TEST(RailTests,GetStatusVout)520 TEST(RailTests, GetStatusVout)
521 {
522 std::string name{"VDD2"};
523 std::optional<std::string> presence{};
524 bool isPowerSupplyRail{false};
525 bool checkStatusVout{false};
526 bool compareVoltageToLimit{false};
527 std::optional<GPIO> gpio{};
528
529 // Test where page was not specified: Throws exception
530 {
531 std::optional<uint8_t> page{};
532 Rail rail{name,
533 presence,
534 page,
535 isPowerSupplyRail,
536 checkStatusVout,
537 compareVoltageToLimit,
538 gpio};
539
540 MockDevice device{};
541 EXPECT_CALL(device, getStatusVout).Times(0);
542
543 try
544 {
545 rail.getStatusVout(device);
546 ADD_FAILURE() << "Should not have reached this line.";
547 }
548 catch (const std::exception& e)
549 {
550 EXPECT_STREQ(e.what(),
551 "Unable to read STATUS_VOUT value for rail VDD2: "
552 "No PAGE number defined for rail VDD2");
553 }
554 }
555
556 // Test where value read successfully
557 {
558 std::optional<uint8_t> page{2};
559 Rail rail{name,
560 presence,
561 page,
562 isPowerSupplyRail,
563 checkStatusVout,
564 compareVoltageToLimit,
565 gpio};
566
567 MockDevice device{};
568 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0xad));
569
570 EXPECT_EQ(rail.getStatusVout(device), 0xad);
571 }
572
573 // Test where exception occurs trying to read value
574 {
575 std::optional<uint8_t> page{2};
576 Rail rail{name,
577 presence,
578 page,
579 isPowerSupplyRail,
580 checkStatusVout,
581 compareVoltageToLimit,
582 gpio};
583
584 MockDevice device{};
585 EXPECT_CALL(device, getStatusVout(2))
586 .Times(1)
587 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
588
589 try
590 {
591 rail.getStatusVout(device);
592 ADD_FAILURE() << "Should not have reached this line.";
593 }
594 catch (const std::exception& e)
595 {
596 EXPECT_STREQ(e.what(),
597 "Unable to read STATUS_VOUT value for rail VDD2: "
598 "File does not exist");
599 }
600 }
601 }
602
TEST(RailTests,GetReadVout)603 TEST(RailTests, GetReadVout)
604 {
605 std::string name{"VDD2"};
606 std::optional<std::string> presence{};
607 bool isPowerSupplyRail{false};
608 bool checkStatusVout{false};
609 bool compareVoltageToLimit{false};
610 std::optional<GPIO> gpio{};
611
612 // Test where page was not specified: Throws exception
613 {
614 std::optional<uint8_t> page{};
615 Rail rail{name,
616 presence,
617 page,
618 isPowerSupplyRail,
619 checkStatusVout,
620 compareVoltageToLimit,
621 gpio};
622
623 MockDevice device{};
624 EXPECT_CALL(device, getReadVout).Times(0);
625
626 try
627 {
628 rail.getReadVout(device);
629 ADD_FAILURE() << "Should not have reached this line.";
630 }
631 catch (const std::exception& e)
632 {
633 EXPECT_STREQ(e.what(),
634 "Unable to read READ_VOUT value for rail VDD2: "
635 "No PAGE number defined for rail VDD2");
636 }
637 }
638
639 // Test where value read successfully
640 {
641 std::optional<uint8_t> page{2};
642 Rail rail{name,
643 presence,
644 page,
645 isPowerSupplyRail,
646 checkStatusVout,
647 compareVoltageToLimit,
648 gpio};
649
650 MockDevice device{};
651 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.23));
652
653 EXPECT_EQ(rail.getReadVout(device), 1.23);
654 }
655
656 // Test where exception occurs trying to read value
657 {
658 std::optional<uint8_t> page{2};
659 Rail rail{name,
660 presence,
661 page,
662 isPowerSupplyRail,
663 checkStatusVout,
664 compareVoltageToLimit,
665 gpio};
666
667 MockDevice device{};
668 EXPECT_CALL(device, getReadVout(2))
669 .Times(1)
670 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
671
672 try
673 {
674 rail.getReadVout(device);
675 ADD_FAILURE() << "Should not have reached this line.";
676 }
677 catch (const std::exception& e)
678 {
679 EXPECT_STREQ(e.what(),
680 "Unable to read READ_VOUT value for rail VDD2: "
681 "File does not exist");
682 }
683 }
684 }
685
TEST(RailTests,GetVoutUVFaultLimit)686 TEST(RailTests, GetVoutUVFaultLimit)
687 {
688 std::string name{"VDD2"};
689 std::optional<std::string> presence{};
690 bool isPowerSupplyRail{false};
691 bool checkStatusVout{false};
692 bool compareVoltageToLimit{false};
693 std::optional<GPIO> gpio{};
694
695 // Test where page was not specified: Throws exception
696 {
697 std::optional<uint8_t> page{};
698 Rail rail{name,
699 presence,
700 page,
701 isPowerSupplyRail,
702 checkStatusVout,
703 compareVoltageToLimit,
704 gpio};
705
706 MockDevice device{};
707 EXPECT_CALL(device, getVoutUVFaultLimit).Times(0);
708
709 try
710 {
711 rail.getVoutUVFaultLimit(device);
712 ADD_FAILURE() << "Should not have reached this line.";
713 }
714 catch (const std::exception& e)
715 {
716 EXPECT_STREQ(
717 e.what(),
718 "Unable to read VOUT_UV_FAULT_LIMIT value for rail VDD2: "
719 "No PAGE number defined for rail VDD2");
720 }
721 }
722
723 // Test where value read successfully
724 {
725 std::optional<uint8_t> page{2};
726 Rail rail{name,
727 presence,
728 page,
729 isPowerSupplyRail,
730 checkStatusVout,
731 compareVoltageToLimit,
732 gpio};
733
734 MockDevice device{};
735 EXPECT_CALL(device, getVoutUVFaultLimit(2))
736 .Times(1)
737 .WillOnce(Return(0.9));
738
739 EXPECT_EQ(rail.getVoutUVFaultLimit(device), 0.9);
740 }
741
742 // Test where exception occurs trying to read value
743 {
744 std::optional<uint8_t> page{2};
745 Rail rail{name,
746 presence,
747 page,
748 isPowerSupplyRail,
749 checkStatusVout,
750 compareVoltageToLimit,
751 gpio};
752
753 MockDevice device{};
754 EXPECT_CALL(device, getVoutUVFaultLimit(2))
755 .Times(1)
756 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
757
758 try
759 {
760 rail.getVoutUVFaultLimit(device);
761 ADD_FAILURE() << "Should not have reached this line.";
762 }
763 catch (const std::exception& e)
764 {
765 EXPECT_STREQ(
766 e.what(),
767 "Unable to read VOUT_UV_FAULT_LIMIT value for rail VDD2: "
768 "File does not exist");
769 }
770 }
771 }
772
TEST(RailTests,HasPgoodFault)773 TEST(RailTests, HasPgoodFault)
774 {
775 std::string name{"VDD2"};
776 std::optional<std::string> presence{};
777 std::optional<uint8_t> page{2};
778 bool isPowerSupplyRail{false};
779 bool checkStatusVout{true};
780 bool compareVoltageToLimit{true};
781 bool activeLow{true};
782 std::optional<GPIO> gpio{GPIO(3, activeLow)};
783 Rail rail{name,
784 presence,
785 page,
786 isPowerSupplyRail,
787 checkStatusVout,
788 compareVoltageToLimit,
789 gpio};
790
791 // No fault detected
792 {
793 MockDevice device{};
794 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00));
795 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1));
796 EXPECT_CALL(device, getVoutUVFaultLimit(2))
797 .Times(1)
798 .WillOnce(Return(1.0));
799
800 MockServices services{};
801
802 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0};
803 std::map<std::string, std::string> additionalData{};
804 EXPECT_FALSE(
805 rail.hasPgoodFault(device, services, gpioValues, additionalData));
806 EXPECT_EQ(additionalData.size(), 0);
807 }
808
809 // Fault detected via STATUS_VOUT
810 {
811 MockDevice device{};
812 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x10));
813 EXPECT_CALL(device, getReadVout(2)).Times(0);
814 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef));
815
816 MockServices services{};
817 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef"))
818 .Times(1);
819 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
820 .Times(1);
821 EXPECT_CALL(
822 services,
823 logErrorMsg("Rail VDD2 has fault bits set in STATUS_VOUT: 0x10"))
824 .Times(1);
825
826 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0};
827 std::map<std::string, std::string> additionalData{};
828 EXPECT_TRUE(
829 rail.hasPgoodFault(device, services, gpioValues, additionalData));
830 EXPECT_EQ(additionalData.size(), 3);
831 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
832 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x10");
833 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
834 }
835
836 // Fault detected via GPIO
837 {
838 MockDevice device{};
839 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00));
840 EXPECT_CALL(device, getReadVout(2)).Times(0);
841 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef));
842
843 MockServices services{};
844 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef"))
845 .Times(1);
846 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
847 .Times(1);
848 EXPECT_CALL(
849 services,
850 logErrorMsg(
851 "Rail VDD2 pgood GPIO line offset 3 has inactive value 1"))
852 .Times(1);
853
854 std::vector<int> gpioValues{0, 0, 0, 1, 0, 0};
855 std::map<std::string, std::string> additionalData{};
856 EXPECT_TRUE(
857 rail.hasPgoodFault(device, services, gpioValues, additionalData));
858 EXPECT_EQ(additionalData.size(), 4);
859 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
860 EXPECT_EQ(additionalData["GPIO_LINE"], "3");
861 EXPECT_EQ(additionalData["GPIO_VALUE"], "1");
862 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
863 }
864
865 // Fault detected via output voltage
866 {
867 MockDevice device{};
868 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00));
869 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1));
870 EXPECT_CALL(device, getVoutUVFaultLimit(2))
871 .Times(1)
872 .WillOnce(Return(1.1));
873 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef));
874
875 MockServices services{};
876 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef"))
877 .Times(1);
878 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
879 .Times(1);
880 EXPECT_CALL(
881 services,
882 logErrorMsg(
883 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.1V"))
884 .Times(1);
885
886 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0};
887 std::map<std::string, std::string> additionalData{};
888 EXPECT_TRUE(
889 rail.hasPgoodFault(device, services, gpioValues, additionalData));
890 EXPECT_EQ(additionalData.size(), 4);
891 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
892 EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
893 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.1");
894 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
895 }
896 }
897
TEST(RailTests,HasPgoodFaultStatusVout)898 TEST(RailTests, HasPgoodFaultStatusVout)
899 {
900 std::string name{"VDD2"};
901 std::optional<uint8_t> page{3};
902 bool isPowerSupplyRail{false};
903 bool compareVoltageToLimit{false};
904 std::optional<GPIO> gpio{};
905
906 // Test where presence check defined: Rail is not present
907 {
908 std::optional<std::string> presence{
909 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
910 bool checkStatusVout{true};
911 Rail rail{name,
912 presence,
913 page,
914 isPowerSupplyRail,
915 checkStatusVout,
916 compareVoltageToLimit,
917 gpio};
918
919 MockDevice device{};
920 EXPECT_CALL(device, getStatusVout(3)).Times(0);
921
922 MockServices services{};
923 EXPECT_CALL(services, isPresent(*presence))
924 .Times(1)
925 .WillOnce(Return(false));
926
927 std::map<std::string, std::string> additionalData{};
928 EXPECT_FALSE(
929 rail.hasPgoodFaultStatusVout(device, services, additionalData));
930 EXPECT_EQ(additionalData.size(), 0);
931 }
932
933 // Test where presence check defined: Rail is present: No fault detected
934 {
935 std::optional<std::string> presence{
936 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
937 bool checkStatusVout{true};
938 Rail rail{name,
939 presence,
940 page,
941 isPowerSupplyRail,
942 checkStatusVout,
943 compareVoltageToLimit,
944 gpio};
945
946 MockDevice device{};
947 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00));
948
949 MockServices services{};
950 EXPECT_CALL(services, isPresent(*presence))
951 .Times(1)
952 .WillOnce(Return(true));
953
954 std::map<std::string, std::string> additionalData{};
955 EXPECT_FALSE(
956 rail.hasPgoodFaultStatusVout(device, services, additionalData));
957 EXPECT_EQ(additionalData.size(), 0);
958 }
959
960 // Test where STATUS_VOUT check is not defined
961 {
962 std::optional<std::string> presence{};
963 bool checkStatusVout{false};
964 Rail rail{name,
965 presence,
966 page,
967 isPowerSupplyRail,
968 checkStatusVout,
969 compareVoltageToLimit,
970 gpio};
971
972 MockDevice device{};
973 EXPECT_CALL(device, getStatusVout(3)).Times(0);
974
975 MockServices services{};
976
977 std::map<std::string, std::string> additionalData{};
978 EXPECT_FALSE(
979 rail.hasPgoodFaultStatusVout(device, services, additionalData));
980 EXPECT_EQ(additionalData.size(), 0);
981 }
982
983 // Test where no fault detected: No warning bits set
984 {
985 std::optional<std::string> presence{};
986 bool checkStatusVout{true};
987 Rail rail{name,
988 presence,
989 page,
990 isPowerSupplyRail,
991 checkStatusVout,
992 compareVoltageToLimit,
993 gpio};
994
995 MockDevice device{};
996 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00));
997
998 MockServices services{};
999 EXPECT_CALL(services, logInfoMsg).Times(0);
1000
1001 std::map<std::string, std::string> additionalData{};
1002 EXPECT_FALSE(
1003 rail.hasPgoodFaultStatusVout(device, services, additionalData));
1004 EXPECT_EQ(additionalData.size(), 0);
1005 }
1006
1007 // Test where no fault detected: Warning bits set
1008 {
1009 std::optional<std::string> presence{};
1010 bool checkStatusVout{true};
1011 Rail rail{name,
1012 presence,
1013 page,
1014 isPowerSupplyRail,
1015 checkStatusVout,
1016 compareVoltageToLimit,
1017 gpio};
1018
1019 MockDevice device{};
1020 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x6a));
1021
1022 MockServices services{};
1023 EXPECT_CALL(
1024 services,
1025 logInfoMsg("Rail VDD2 has warning bits set in STATUS_VOUT: 0x6a"))
1026 .Times(1);
1027
1028 std::map<std::string, std::string> additionalData{};
1029 EXPECT_FALSE(
1030 rail.hasPgoodFaultStatusVout(device, services, additionalData));
1031 EXPECT_EQ(additionalData.size(), 0);
1032 }
1033
1034 // Test where fault detected
1035 // STATUS_WORD captured in additional data
1036 {
1037 std::optional<std::string> presence{};
1038 bool checkStatusVout{true};
1039 Rail rail{name,
1040 presence,
1041 page,
1042 isPowerSupplyRail,
1043 checkStatusVout,
1044 compareVoltageToLimit,
1045 gpio};
1046
1047 MockDevice device{};
1048 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x10));
1049 EXPECT_CALL(device, getStatusWord(3)).Times(1).WillOnce(Return(0xbeef));
1050
1051 MockServices services{};
1052 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef"))
1053 .Times(1);
1054 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
1055 .Times(1);
1056 EXPECT_CALL(
1057 services,
1058 logErrorMsg("Rail VDD2 has fault bits set in STATUS_VOUT: 0x10"))
1059 .Times(1);
1060
1061 std::map<std::string, std::string> additionalData{};
1062 EXPECT_TRUE(
1063 rail.hasPgoodFaultStatusVout(device, services, additionalData));
1064 EXPECT_EQ(additionalData.size(), 3);
1065 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
1066 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x10");
1067 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
1068 }
1069
1070 // Test where exception thrown
1071 {
1072 std::optional<std::string> presence{};
1073 bool checkStatusVout{true};
1074 Rail rail{name,
1075 presence,
1076 page,
1077 isPowerSupplyRail,
1078 checkStatusVout,
1079 compareVoltageToLimit,
1080 gpio};
1081
1082 MockDevice device{};
1083 EXPECT_CALL(device, getStatusVout(3))
1084 .Times(1)
1085 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
1086
1087 MockServices services{};
1088
1089 std::map<std::string, std::string> additionalData{};
1090 try
1091 {
1092 rail.hasPgoodFaultStatusVout(device, services, additionalData);
1093 ADD_FAILURE() << "Should not have reached this line.";
1094 }
1095 catch (const std::exception& e)
1096 {
1097 EXPECT_STREQ(e.what(),
1098 "Unable to read STATUS_VOUT value for rail VDD2: "
1099 "File does not exist");
1100 }
1101 }
1102 }
1103
TEST(RailTests,HasPgoodFaultGPIO)1104 TEST(RailTests, HasPgoodFaultGPIO)
1105 {
1106 std::string name{"VDD2"};
1107 bool isPowerSupplyRail{false};
1108 bool checkStatusVout{false};
1109 bool compareVoltageToLimit{false};
1110
1111 // Test where presence check defined: Rail is not present
1112 {
1113 std::optional<std::string> presence{
1114 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
1115 std::optional<uint8_t> page{3};
1116 bool activeLow{false};
1117 std::optional<GPIO> gpio{GPIO(3, activeLow)};
1118 Rail rail{name,
1119 presence,
1120 page,
1121 isPowerSupplyRail,
1122 checkStatusVout,
1123 compareVoltageToLimit,
1124 gpio};
1125
1126 MockDevice device{};
1127
1128 MockServices services{};
1129 EXPECT_CALL(services, isPresent(*presence))
1130 .Times(1)
1131 .WillOnce(Return(false));
1132
1133 std::vector<int> gpioValues{1, 1, 1, 0, 1, 1};
1134 std::map<std::string, std::string> additionalData{};
1135 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues,
1136 additionalData));
1137 EXPECT_EQ(additionalData.size(), 0);
1138 }
1139
1140 // Test where presence check defined: Rail is present: No fault detected
1141 {
1142 std::optional<std::string> presence{
1143 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
1144 std::optional<uint8_t> page{3};
1145 bool activeLow{false};
1146 std::optional<GPIO> gpio{GPIO(3, activeLow)};
1147 Rail rail{name,
1148 presence,
1149 page,
1150 isPowerSupplyRail,
1151 checkStatusVout,
1152 compareVoltageToLimit,
1153 gpio};
1154
1155 MockDevice device{};
1156
1157 MockServices services{};
1158 EXPECT_CALL(services, isPresent(*presence))
1159 .Times(1)
1160 .WillOnce(Return(true));
1161
1162 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1};
1163 std::map<std::string, std::string> additionalData{};
1164 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues,
1165 additionalData));
1166 EXPECT_EQ(additionalData.size(), 0);
1167 }
1168
1169 // Test where GPIO check not defined
1170 {
1171 std::optional<std::string> presence{};
1172 std::optional<uint8_t> page{3};
1173 std::optional<GPIO> gpio{};
1174 Rail rail{name,
1175 presence,
1176 page,
1177 isPowerSupplyRail,
1178 checkStatusVout,
1179 compareVoltageToLimit,
1180 gpio};
1181
1182 MockDevice device{};
1183
1184 MockServices services{};
1185
1186 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0};
1187 std::map<std::string, std::string> additionalData{};
1188 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues,
1189 additionalData));
1190 EXPECT_EQ(additionalData.size(), 0);
1191 }
1192
1193 // Test where no fault detected
1194 // GPIO value is 1 and GPIO is active high
1195 {
1196 std::optional<std::string> presence{};
1197 std::optional<uint8_t> page{};
1198 bool activeLow{false};
1199 std::optional<GPIO> gpio{GPIO(3, activeLow)};
1200 Rail rail{name,
1201 presence,
1202 page,
1203 isPowerSupplyRail,
1204 checkStatusVout,
1205 compareVoltageToLimit,
1206 gpio};
1207
1208 MockDevice device{};
1209
1210 MockServices services{};
1211
1212 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1};
1213 std::map<std::string, std::string> additionalData{};
1214 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues,
1215 additionalData));
1216 EXPECT_EQ(additionalData.size(), 0);
1217 }
1218
1219 // Test where fault detected
1220 // GPIO value is 0 and GPIO is active high
1221 // STATUS_WORD not captured since no PMBus page defined
1222 {
1223 std::optional<std::string> presence{};
1224 std::optional<uint8_t> page{};
1225 bool activeLow{false};
1226 std::optional<GPIO> gpio{GPIO(3, activeLow)};
1227 Rail rail{name,
1228 presence,
1229 page,
1230 isPowerSupplyRail,
1231 checkStatusVout,
1232 compareVoltageToLimit,
1233 gpio};
1234
1235 MockDevice device{};
1236
1237 MockServices services{};
1238 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
1239 .Times(1);
1240 EXPECT_CALL(
1241 services,
1242 logErrorMsg(
1243 "Rail VDD2 pgood GPIO line offset 3 has inactive value 0"))
1244 .Times(1);
1245
1246 std::vector<int> gpioValues{1, 1, 1, 0, 1, 1};
1247 std::map<std::string, std::string> additionalData{};
1248 EXPECT_TRUE(rail.hasPgoodFaultGPIO(device, services, gpioValues,
1249 additionalData));
1250 EXPECT_EQ(additionalData.size(), 3);
1251 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
1252 EXPECT_EQ(additionalData["GPIO_LINE"], "3");
1253 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
1254 }
1255
1256 // Test where fault detected
1257 // GPIO value is 1 and GPIO is active low
1258 {
1259 std::optional<std::string> presence{};
1260 std::optional<uint8_t> page{2};
1261 bool activeLow{true};
1262 std::optional<GPIO> gpio{GPIO(3, activeLow)};
1263 Rail rail{name,
1264 presence,
1265 page,
1266 isPowerSupplyRail,
1267 checkStatusVout,
1268 compareVoltageToLimit,
1269 gpio};
1270
1271 MockDevice device{};
1272 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef));
1273
1274 MockServices services{};
1275 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef"))
1276 .Times(1);
1277 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
1278 .Times(1);
1279 EXPECT_CALL(
1280 services,
1281 logErrorMsg(
1282 "Rail VDD2 pgood GPIO line offset 3 has inactive value 1"))
1283 .Times(1);
1284
1285 std::vector<int> gpioValues{0, 0, 0, 1, 0, 0};
1286 std::map<std::string, std::string> additionalData{};
1287 EXPECT_TRUE(rail.hasPgoodFaultGPIO(device, services, gpioValues,
1288 additionalData));
1289 EXPECT_EQ(additionalData.size(), 4);
1290 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
1291 EXPECT_EQ(additionalData["GPIO_LINE"], "3");
1292 EXPECT_EQ(additionalData["GPIO_VALUE"], "1");
1293 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
1294 }
1295
1296 // Test where exception thrown
1297 {
1298 std::optional<std::string> presence{};
1299 std::optional<uint8_t> page{};
1300 bool activeLow{false};
1301 std::optional<GPIO> gpio{GPIO(6, activeLow)};
1302 Rail rail{name,
1303 presence,
1304 page,
1305 isPowerSupplyRail,
1306 checkStatusVout,
1307 compareVoltageToLimit,
1308 gpio};
1309
1310 MockDevice device{};
1311
1312 MockServices services{};
1313
1314 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1};
1315 std::map<std::string, std::string> additionalData{};
1316 try
1317 {
1318 rail.hasPgoodFaultGPIO(device, services, gpioValues,
1319 additionalData);
1320 ADD_FAILURE() << "Should not have reached this line.";
1321 }
1322 catch (const std::exception& e)
1323 {
1324 EXPECT_STREQ(e.what(), "Invalid GPIO line offset 6 for rail VDD2: "
1325 "Device only has 6 GPIO values");
1326 }
1327 }
1328 }
1329
TEST(RailTests,HasPgoodFaultOutputVoltage)1330 TEST(RailTests, HasPgoodFaultOutputVoltage)
1331 {
1332 std::string name{"VDD2"};
1333 std::optional<uint8_t> page{2};
1334 bool isPowerSupplyRail{false};
1335 bool checkStatusVout{false};
1336 std::optional<GPIO> gpio{};
1337
1338 // Test where presence check defined: Rail is not present
1339 {
1340 std::optional<std::string> presence{
1341 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
1342 bool compareVoltageToLimit{true};
1343 Rail rail{name,
1344 presence,
1345 page,
1346 isPowerSupplyRail,
1347 checkStatusVout,
1348 compareVoltageToLimit,
1349 gpio};
1350
1351 MockDevice device{};
1352 EXPECT_CALL(device, getReadVout(2)).Times(0);
1353 EXPECT_CALL(device, getVoutUVFaultLimit(2)).Times(0);
1354
1355 MockServices services{};
1356 EXPECT_CALL(services, isPresent(*presence))
1357 .Times(1)
1358 .WillOnce(Return(false));
1359
1360 std::map<std::string, std::string> additionalData{};
1361 EXPECT_FALSE(
1362 rail.hasPgoodFaultOutputVoltage(device, services, additionalData));
1363 EXPECT_EQ(additionalData.size(), 0);
1364 }
1365
1366 // Test where presence check defined: Rail is present: No fault detected
1367 {
1368 std::optional<std::string> presence{
1369 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"};
1370 bool compareVoltageToLimit{true};
1371 Rail rail{name,
1372 presence,
1373 page,
1374 isPowerSupplyRail,
1375 checkStatusVout,
1376 compareVoltageToLimit,
1377 gpio};
1378
1379 MockDevice device{};
1380 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1));
1381 EXPECT_CALL(device, getVoutUVFaultLimit(2))
1382 .Times(1)
1383 .WillOnce(Return(1.0));
1384
1385 MockServices services{};
1386 EXPECT_CALL(services, isPresent(*presence))
1387 .Times(1)
1388 .WillOnce(Return(true));
1389
1390 std::map<std::string, std::string> additionalData{};
1391 EXPECT_FALSE(
1392 rail.hasPgoodFaultOutputVoltage(device, services, additionalData));
1393 EXPECT_EQ(additionalData.size(), 0);
1394 }
1395
1396 // Test where voltage output check not specified
1397 {
1398 std::optional<std::string> presence{};
1399 bool compareVoltageToLimit{false};
1400 Rail rail{name,
1401 presence,
1402 page,
1403 isPowerSupplyRail,
1404 checkStatusVout,
1405 compareVoltageToLimit,
1406 gpio};
1407
1408 MockDevice device{};
1409 EXPECT_CALL(device, getReadVout(2)).Times(0);
1410 EXPECT_CALL(device, getVoutUVFaultLimit(2)).Times(0);
1411
1412 MockServices services{};
1413
1414 std::map<std::string, std::string> additionalData{};
1415 EXPECT_FALSE(
1416 rail.hasPgoodFaultOutputVoltage(device, services, additionalData));
1417 EXPECT_EQ(additionalData.size(), 0);
1418 }
1419
1420 // Test where no fault detected: Output voltage > UV limit
1421 {
1422 std::optional<std::string> presence{};
1423 bool compareVoltageToLimit{true};
1424 Rail rail{name,
1425 presence,
1426 page,
1427 isPowerSupplyRail,
1428 checkStatusVout,
1429 compareVoltageToLimit,
1430 gpio};
1431
1432 MockDevice device{};
1433 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1));
1434 EXPECT_CALL(device, getVoutUVFaultLimit(2))
1435 .Times(1)
1436 .WillOnce(Return(1.0));
1437
1438 MockServices services{};
1439
1440 std::map<std::string, std::string> additionalData{};
1441 EXPECT_FALSE(
1442 rail.hasPgoodFaultOutputVoltage(device, services, additionalData));
1443 EXPECT_EQ(additionalData.size(), 0);
1444 }
1445
1446 // Test where fault detected: Output voltage < UV limit
1447 {
1448 std::optional<std::string> presence{};
1449 bool compareVoltageToLimit{true};
1450 Rail rail{name,
1451 presence,
1452 page,
1453 isPowerSupplyRail,
1454 checkStatusVout,
1455 compareVoltageToLimit,
1456 gpio};
1457
1458 MockDevice device{};
1459 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1));
1460 EXPECT_CALL(device, getVoutUVFaultLimit(2))
1461 .Times(1)
1462 .WillOnce(Return(1.2));
1463 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef));
1464
1465 MockServices services{};
1466 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef"))
1467 .Times(1);
1468 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
1469 .Times(1);
1470 EXPECT_CALL(
1471 services,
1472 logErrorMsg(
1473 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.2V"))
1474 .Times(1);
1475
1476 std::map<std::string, std::string> additionalData{};
1477 EXPECT_TRUE(
1478 rail.hasPgoodFaultOutputVoltage(device, services, additionalData));
1479 EXPECT_EQ(additionalData.size(), 4);
1480 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
1481 EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
1482 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2");
1483 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
1484 }
1485
1486 // Test where fault detected: Output voltage == UV limit
1487 // STATUS_WORD not captured because reading it caused an exception
1488 {
1489 std::optional<std::string> presence{};
1490 bool compareVoltageToLimit{true};
1491 Rail rail{name,
1492 presence,
1493 page,
1494 isPowerSupplyRail,
1495 checkStatusVout,
1496 compareVoltageToLimit,
1497 gpio};
1498
1499 MockDevice device{};
1500 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1));
1501 EXPECT_CALL(device, getVoutUVFaultLimit(2))
1502 .Times(1)
1503 .WillOnce(Return(1.1));
1504 EXPECT_CALL(device, getStatusWord(2))
1505 .Times(1)
1506 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
1507
1508 MockServices services{};
1509 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2"))
1510 .Times(1);
1511 EXPECT_CALL(
1512 services,
1513 logErrorMsg(
1514 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.1V"))
1515 .Times(1);
1516
1517 std::map<std::string, std::string> additionalData{};
1518 EXPECT_TRUE(
1519 rail.hasPgoodFaultOutputVoltage(device, services, additionalData));
1520 EXPECT_EQ(additionalData.size(), 3);
1521 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2");
1522 EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
1523 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.1");
1524 }
1525
1526 // Test where exception thrown
1527 {
1528 std::optional<std::string> presence{};
1529 bool compareVoltageToLimit{true};
1530 Rail rail{name,
1531 presence,
1532 page,
1533 isPowerSupplyRail,
1534 checkStatusVout,
1535 compareVoltageToLimit,
1536 gpio};
1537
1538 MockDevice device{};
1539 EXPECT_CALL(device, getReadVout(2))
1540 .Times(1)
1541 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
1542
1543 MockServices services{};
1544
1545 std::map<std::string, std::string> additionalData{};
1546 try
1547 {
1548 rail.hasPgoodFaultOutputVoltage(device, services, additionalData);
1549 ADD_FAILURE() << "Should not have reached this line.";
1550 }
1551 catch (const std::exception& e)
1552 {
1553 EXPECT_STREQ(e.what(),
1554 "Unable to read READ_VOUT value for rail VDD2: "
1555 "File does not exist");
1556 }
1557 }
1558 }
1559