xref: /openbmc/phosphor-power/phosphor-power-sequencer/test/basic_device_tests.cpp (revision 77c1c26ff2a90bfbbd80eb6d35366f49ce70eb87)
1 /**
2  * Copyright © 2025 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 "basic_device.hpp"
18 #include "mock_gpio.hpp"
19 #include "mock_services.hpp"
20 #include "rail.hpp"
21 #include "services.hpp"
22 
23 #include <cstdint>
24 #include <map>
25 #include <memory>
26 #include <optional>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 
31 #include <gmock/gmock.h>
32 #include <gtest/gtest.h>
33 
34 using namespace phosphor::power::sequencer;
35 
36 using ::testing::Return;
37 using ::testing::Throw;
38 
39 /**
40  * @class BasicDeviceImpl
41  *
42  * Concrete subclass of the BasicDevice abstract class.
43  *
44  * This subclass is required because BasicDevice does not implement all the pure
45  * virtual methods inherited for PowerSequencerDevice, meaning it cannot be
46  * instantiated.
47  *
48  * This class is not intended to be used outside of this file.  It is
49  * implementation detail for testing the BasicDevice class.
50  */
51 class BasicDeviceImpl : public BasicDevice
52 {
53   public:
54     BasicDeviceImpl() = delete;
55     BasicDeviceImpl(const BasicDeviceImpl&) = delete;
56     BasicDeviceImpl(BasicDeviceImpl&&) = delete;
57     BasicDeviceImpl& operator=(const BasicDeviceImpl&) = delete;
58     BasicDeviceImpl& operator=(BasicDeviceImpl&&) = delete;
59     virtual ~BasicDeviceImpl() = default;
60 
BasicDeviceImpl(const std::string & name,uint8_t bus,uint16_t address,const std::string & powerControlGPIOName,const std::string & powerGoodGPIOName,std::vector<std::unique_ptr<Rail>> rails)61     explicit BasicDeviceImpl(const std::string& name, uint8_t bus,
62                              uint16_t address,
63                              const std::string& powerControlGPIOName,
64                              const std::string& powerGoodGPIOName,
65                              std::vector<std::unique_ptr<Rail>> rails) :
66         BasicDevice(name, bus, address, powerControlGPIOName, powerGoodGPIOName,
67                     std::move(rails))
68     {}
69 
70     // Mock pure virtual methods
71     MOCK_METHOD(std::vector<int>, getGPIOValues, (Services & services),
72                 (override));
73     MOCK_METHOD(uint16_t, getStatusWord, (uint8_t page), (override));
74     MOCK_METHOD(uint8_t, getStatusVout, (uint8_t page), (override));
75     MOCK_METHOD(double, getReadVout, (uint8_t page), (override));
76     MOCK_METHOD(double, getVoutUVFaultLimit, (uint8_t page), (override));
77     MOCK_METHOD(std::string, findPgoodFault,
78                 (Services & services, const std::string& powerSupplyError,
79                  (std::map<std::string, std::string> & additionalData)),
80                 (override));
81 };
82 
83 /**
84  * Creates a Rail object that checks for a pgood fault using a GPIO.
85  *
86  * @param name Unique name for the rail
87  * @param gpio GPIO line to read to determine the pgood status of the rail
88  * @return Rail object
89  */
createRail(const std::string & name,unsigned int gpioLine)90 static std::unique_ptr<Rail> createRail(const std::string& name,
91                                         unsigned int gpioLine)
92 {
93     std::optional<std::string> presence{};
94     std::optional<uint8_t> page{};
95     bool isPowerSupplyRail{false};
96     bool checkStatusVout{false};
97     bool compareVoltageToLimit{false};
98     bool activeLow{false};
99     std::optional<PgoodGPIO> gpio{PgoodGPIO{gpioLine, activeLow}};
100     return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
101                                   checkStatusVout, compareVoltageToLimit, gpio);
102 }
103 
TEST(BasicDeviceTests,Constructor)104 TEST(BasicDeviceTests, Constructor)
105 {
106     // Test where works: Empty vector of rails
107     {
108         std::string name{"xyz_pseq"};
109         uint8_t bus{3};
110         uint16_t address{0x72};
111         std::string powerControlGPIOName{"power-chassis-control"};
112         std::string powerGoodGPIOName{"power-chassis-good"};
113         std::vector<std::unique_ptr<Rail>> rails{};
114         BasicDeviceImpl device{name,
115                                bus,
116                                address,
117                                powerControlGPIOName,
118                                powerGoodGPIOName,
119                                std::move(rails)};
120 
121         EXPECT_EQ(device.getName(), name);
122         EXPECT_EQ(device.getBus(), bus);
123         EXPECT_EQ(device.getAddress(), address);
124         EXPECT_EQ(device.getPowerControlGPIOName(), powerControlGPIOName);
125         EXPECT_EQ(device.getPowerGoodGPIOName(), powerGoodGPIOName);
126         EXPECT_TRUE(device.getRails().empty());
127         EXPECT_FALSE(device.isOpen());
128     }
129 
130     // Test where works: Non-empty vector of rails
131     {
132         std::string name{"abc_pseq"};
133         uint8_t bus{0};
134         uint16_t address{0x23};
135         std::string powerControlGPIOName{"power-chassis-control"};
136         std::string powerGoodGPIOName{"power-chassis-good"};
137         std::vector<std::unique_ptr<Rail>> rails{};
138         rails.emplace_back(createRail("VDD", 5));
139         rails.emplace_back(createRail("VIO", 7));
140         BasicDeviceImpl device{name,
141                                bus,
142                                address,
143                                powerControlGPIOName,
144                                powerGoodGPIOName,
145                                std::move(rails)};
146 
147         EXPECT_EQ(device.getName(), name);
148         EXPECT_EQ(device.getBus(), bus);
149         EXPECT_EQ(device.getAddress(), address);
150         EXPECT_EQ(device.getPowerControlGPIOName(), powerControlGPIOName);
151         EXPECT_EQ(device.getPowerGoodGPIOName(), powerGoodGPIOName);
152         EXPECT_EQ(device.getRails().size(), 2);
153         EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
154         EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
155         EXPECT_FALSE(device.isOpen());
156     }
157 }
158 
TEST(BasicDeviceTests,Destructor)159 TEST(BasicDeviceTests, Destructor)
160 {
161     // Test where succeeds: No exception thrown
162     {
163         std::string name{"xyz_pseq"};
164         uint8_t bus{0};
165         uint16_t address{0x23};
166         std::string powerControlGPIOName{"power-chassis-control"};
167         std::string powerGoodGPIOName{"power-chassis-good"};
168         std::vector<std::unique_ptr<Rail>> rails{};
169         BasicDeviceImpl device{name,
170                                bus,
171                                address,
172                                powerControlGPIOName,
173                                powerGoodGPIOName,
174                                std::move(rails)};
175         MockServices services;
176         device.open(services);
177     }
178 
179     // Test where succeeds: Exception caught
180     {
181         std::string name{"xyz_pseq"};
182         uint8_t bus{0};
183         uint16_t address{0x23};
184         std::string powerControlGPIOName{"power-chassis-control"};
185         std::string powerGoodGPIOName{"power-chassis-good"};
186         std::vector<std::unique_ptr<Rail>> rails{};
187         BasicDeviceImpl device{name,
188                                bus,
189                                address,
190                                powerControlGPIOName,
191                                powerGoodGPIOName,
192                                std::move(rails)};
193         MockServices services;
194         device.open(services);
195         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
196         EXPECT_CALL(gpio, release)
197             .Times(1)
198             .WillOnce(Throw(std::runtime_error{"Unable to release GPIO"}));
199     }
200 }
201 
TEST(BasicDeviceTests,GetName)202 TEST(BasicDeviceTests, GetName)
203 {
204     std::string name{"xyz_pseq"};
205     uint8_t bus{0};
206     uint16_t address{0x23};
207     std::string powerControlGPIOName{"power-chassis-control"};
208     std::string powerGoodGPIOName{"power-chassis-good"};
209     std::vector<std::unique_ptr<Rail>> rails{};
210     BasicDeviceImpl device{name,
211                            bus,
212                            address,
213                            powerControlGPIOName,
214                            powerGoodGPIOName,
215                            std::move(rails)};
216 
217     EXPECT_EQ(device.getName(), name);
218 }
219 
TEST(BasicDeviceTests,GetBus)220 TEST(BasicDeviceTests, GetBus)
221 {
222     std::string name{"abc_pseq"};
223     uint8_t bus{1};
224     uint16_t address{0x23};
225     std::string powerControlGPIOName{"power-chassis-control"};
226     std::string powerGoodGPIOName{"power-chassis-good"};
227     std::vector<std::unique_ptr<Rail>> rails{};
228     BasicDeviceImpl device{name,
229                            bus,
230                            address,
231                            powerControlGPIOName,
232                            powerGoodGPIOName,
233                            std::move(rails)};
234 
235     EXPECT_EQ(device.getBus(), bus);
236 }
237 
TEST(BasicDeviceTests,GetAddress)238 TEST(BasicDeviceTests, GetAddress)
239 {
240     std::string name{"abc_pseq"};
241     uint8_t bus{1};
242     uint16_t address{0x24};
243     std::string powerControlGPIOName{"power-chassis-control"};
244     std::string powerGoodGPIOName{"power-chassis-good"};
245     std::vector<std::unique_ptr<Rail>> rails{};
246     BasicDeviceImpl device{name,
247                            bus,
248                            address,
249                            powerControlGPIOName,
250                            powerGoodGPIOName,
251                            std::move(rails)};
252 
253     EXPECT_EQ(device.getAddress(), address);
254 }
255 
TEST(BasicDeviceTests,GetPowerControlGPIOName)256 TEST(BasicDeviceTests, GetPowerControlGPIOName)
257 {
258     std::string name{"xyz_pseq"};
259     uint8_t bus{0};
260     uint16_t address{0x23};
261     std::string powerControlGPIOName{"power-on"};
262     std::string powerGoodGPIOName{"chassis-pgood"};
263     std::vector<std::unique_ptr<Rail>> rails{};
264     BasicDeviceImpl device{name,
265                            bus,
266                            address,
267                            powerControlGPIOName,
268                            powerGoodGPIOName,
269                            std::move(rails)};
270 
271     EXPECT_EQ(device.getPowerControlGPIOName(), powerControlGPIOName);
272 }
273 
TEST(BasicDeviceTests,GetPowerGoodGPIOName)274 TEST(BasicDeviceTests, GetPowerGoodGPIOName)
275 {
276     std::string name{"xyz_pseq"};
277     uint8_t bus{0};
278     uint16_t address{0x23};
279     std::string powerControlGPIOName{"power-on"};
280     std::string powerGoodGPIOName{"chassis-pgood"};
281     std::vector<std::unique_ptr<Rail>> rails{};
282     BasicDeviceImpl device{name,
283                            bus,
284                            address,
285                            powerControlGPIOName,
286                            powerGoodGPIOName,
287                            std::move(rails)};
288 
289     EXPECT_EQ(device.getPowerGoodGPIOName(), powerGoodGPIOName);
290 }
291 
TEST(BasicDeviceTests,GetRails)292 TEST(BasicDeviceTests, GetRails)
293 {
294     // Empty vector of rails
295     {
296         std::string name{"xyz_pseq"};
297         uint8_t bus{0};
298         uint16_t address{0x23};
299         std::string powerControlGPIOName{"power-chassis-control"};
300         std::string powerGoodGPIOName{"power-chassis-good"};
301         std::vector<std::unique_ptr<Rail>> rails{};
302         BasicDeviceImpl device{name,
303                                bus,
304                                address,
305                                powerControlGPIOName,
306                                powerGoodGPIOName,
307                                std::move(rails)};
308 
309         EXPECT_TRUE(device.getRails().empty());
310     }
311 
312     // Non-empty vector of rails
313     {
314         std::string name{"abc_pseq"};
315         uint8_t bus{0};
316         uint16_t address{0x23};
317         std::string powerControlGPIOName{"power-chassis-control"};
318         std::string powerGoodGPIOName{"power-chassis-good"};
319         std::vector<std::unique_ptr<Rail>> rails{};
320         rails.emplace_back(createRail("VDD", 5));
321         rails.emplace_back(createRail("VIO", 7));
322         rails.emplace_back(createRail("VDDR", 9));
323         BasicDeviceImpl device{name,
324                                bus,
325                                address,
326                                powerControlGPIOName,
327                                powerGoodGPIOName,
328                                std::move(rails)};
329 
330         EXPECT_EQ(device.getRails().size(), 3);
331         EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
332         EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
333         EXPECT_EQ(device.getRails()[2]->getName(), "VDDR");
334     }
335 }
336 
TEST(BasicDeviceTests,Open)337 TEST(BasicDeviceTests, Open)
338 {
339     std::string name{"xyz_pseq"};
340     uint8_t bus{0};
341     uint16_t address{0x23};
342     std::string powerControlGPIOName{"power-chassis-control"};
343     std::string powerGoodGPIOName{"power-chassis-good"};
344     std::vector<std::unique_ptr<Rail>> rails{};
345     BasicDeviceImpl device{name,
346                            bus,
347                            address,
348                            powerControlGPIOName,
349                            powerGoodGPIOName,
350                            std::move(rails)};
351 
352     // Test where works
353     EXPECT_FALSE(device.isOpen());
354     MockServices services;
355     device.open(services);
356     EXPECT_TRUE(device.isOpen());
357 
358     MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerControlGPIO());
359     EXPECT_CALL(gpio, setValue(1)).Times(1);
360     device.powerOn();
361 
362     // Test where does nothing because device is already open
363     device.open(services);
364     EXPECT_TRUE(device.isOpen());
365 }
366 
TEST(BasicDeviceTests,IsOpen)367 TEST(BasicDeviceTests, IsOpen)
368 {
369     std::string name{"xyz_pseq"};
370     uint8_t bus{0};
371     uint16_t address{0x23};
372     std::string powerControlGPIOName{"power-chassis-control"};
373     std::string powerGoodGPIOName{"power-chassis-good"};
374     std::vector<std::unique_ptr<Rail>> rails{};
375     BasicDeviceImpl device{name,
376                            bus,
377                            address,
378                            powerControlGPIOName,
379                            powerGoodGPIOName,
380                            std::move(rails)};
381 
382     MockServices services;
383     device.open(services);
384     EXPECT_TRUE(device.isOpen());
385     device.close();
386     EXPECT_FALSE(device.isOpen());
387 }
388 
TEST(BasicDeviceTests,Close)389 TEST(BasicDeviceTests, Close)
390 {
391     // Test where works
392     {
393         std::string name{"xyz_pseq"};
394         uint8_t bus{0};
395         uint16_t address{0x23};
396         std::string powerControlGPIOName{"power-chassis-control"};
397         std::string powerGoodGPIOName{"power-chassis-good"};
398         std::vector<std::unique_ptr<Rail>> rails{};
399         BasicDeviceImpl device{name,
400                                bus,
401                                address,
402                                powerControlGPIOName,
403                                powerGoodGPIOName,
404                                std::move(rails)};
405 
406         MockServices services;
407         device.open(services);
408         EXPECT_TRUE(device.isOpen());
409 
410         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
411         EXPECT_CALL(gpio, release).Times(1);
412         device.close();
413         EXPECT_FALSE(device.isOpen());
414 
415         // Test where does nothing because device already closed
416         device.close();
417         EXPECT_FALSE(device.isOpen());
418     }
419 
420     // Test where fails: Exception thrown
421     try
422     {
423         std::string name{"xyz_pseq"};
424         uint8_t bus{0};
425         uint16_t address{0x23};
426         std::string powerControlGPIOName{"power-chassis-control"};
427         std::string powerGoodGPIOName{"power-chassis-good"};
428         std::vector<std::unique_ptr<Rail>> rails{};
429         BasicDeviceImpl device{name,
430                                bus,
431                                address,
432                                powerControlGPIOName,
433                                powerGoodGPIOName,
434                                std::move(rails)};
435 
436         MockServices services;
437         device.open(services);
438         EXPECT_TRUE(device.isOpen());
439         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
440         // Note: release() called twice. Once directly and once by destructor.
441         EXPECT_CALL(gpio, release)
442             .Times(2)
443             .WillOnce(Throw(std::runtime_error{"Unable to release GPIO"}))
444             .WillOnce(Return());
445         device.close();
446         ADD_FAILURE() << "Should not have reached this line.";
447     }
448     catch (const std::exception& e)
449     {
450         EXPECT_STREQ(e.what(), "Unable to release GPIO");
451     }
452 }
453 
TEST(BasicDeviceTests,CloseWithoutException)454 TEST(BasicDeviceTests, CloseWithoutException)
455 {
456     std::string name{"xyz_pseq"};
457     uint8_t bus{0};
458     uint16_t address{0x23};
459     std::string powerControlGPIOName{"power-chassis-control"};
460     std::string powerGoodGPIOName{"power-chassis-good"};
461     std::vector<std::unique_ptr<Rail>> rails{};
462     BasicDeviceImpl device{name,
463                            bus,
464                            address,
465                            powerControlGPIOName,
466                            powerGoodGPIOName,
467                            std::move(rails)};
468 
469     // Test where works: No exception thrown by close()
470     MockServices services;
471     device.open(services);
472     EXPECT_TRUE(device.isOpen());
473     device.closeWithoutException();
474     EXPECT_FALSE(device.isOpen());
475 
476     // Test where partially works: Exception thrown by close() and caught
477     device.open(services);
478     EXPECT_TRUE(device.isOpen());
479     MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
480     EXPECT_CALL(gpio, release)
481         .Times(2)
482         .WillOnce(Throw(std::runtime_error{"Unable to release GPIO"}))
483         .WillOnce(Return());
484     device.closeWithoutException();
485     EXPECT_TRUE(device.isOpen());
486 
487     // Test where works: Second call to close() does not throw an exception
488     device.closeWithoutException();
489     EXPECT_FALSE(device.isOpen());
490 }
491 
TEST(BasicDeviceTests,GetPowerControlGPIO)492 TEST(BasicDeviceTests, GetPowerControlGPIO)
493 {
494     std::string name{"xyz_pseq"};
495     uint8_t bus{0};
496     uint16_t address{0x23};
497     std::string powerControlGPIOName{"power-on"};
498     std::string powerGoodGPIOName{"chassis-pgood"};
499     std::vector<std::unique_ptr<Rail>> rails{};
500     BasicDeviceImpl device{name,
501                            bus,
502                            address,
503                            powerControlGPIOName,
504                            powerGoodGPIOName,
505                            std::move(rails)};
506 
507     // Test where fails: Device not open
508     try
509     {
510         EXPECT_FALSE(device.isOpen());
511         device.getPowerControlGPIO();
512         ADD_FAILURE() << "Should not have reached this line.";
513     }
514     catch (const std::exception& e)
515     {
516         EXPECT_STREQ(e.what(), "Device not open: xyz_pseq");
517     }
518 
519     // Test where works
520     {
521         MockServices services;
522         device.open(services);
523         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerControlGPIO());
524         EXPECT_CALL(gpio, setValue(1)).Times(1);
525         device.powerOn();
526     }
527 }
528 
TEST(BasicDeviceTests,GetPowerGoodGPIO)529 TEST(BasicDeviceTests, GetPowerGoodGPIO)
530 {
531     std::string name{"xyz_pseq"};
532     uint8_t bus{0};
533     uint16_t address{0x23};
534     std::string powerControlGPIOName{"power-on"};
535     std::string powerGoodGPIOName{"chassis-pgood"};
536     std::vector<std::unique_ptr<Rail>> rails{};
537     BasicDeviceImpl device{name,
538                            bus,
539                            address,
540                            powerControlGPIOName,
541                            powerGoodGPIOName,
542                            std::move(rails)};
543 
544     // Test where fails: Device not open
545     try
546     {
547         EXPECT_FALSE(device.isOpen());
548         device.getPowerGoodGPIO();
549         ADD_FAILURE() << "Should not have reached this line.";
550     }
551     catch (const std::exception& e)
552     {
553         EXPECT_STREQ(e.what(), "Device not open: xyz_pseq");
554     }
555 
556     // Test where works
557     {
558         MockServices services;
559         device.open(services);
560         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
561         EXPECT_CALL(gpio, getValue()).Times(1).WillOnce(Return(0));
562         EXPECT_FALSE(device.getPowerGood());
563     }
564 }
565 
TEST(BasicDeviceTests,PowerOn)566 TEST(BasicDeviceTests, PowerOn)
567 {
568     // Test where fails: Device not open
569     try
570     {
571         std::string name{"xyz_pseq"};
572         uint8_t bus{0};
573         uint16_t address{0x23};
574         std::string powerControlGPIOName{"power-on"};
575         std::string powerGoodGPIOName{"chassis-pgood"};
576         std::vector<std::unique_ptr<Rail>> rails{};
577         BasicDeviceImpl device{name,
578                                bus,
579                                address,
580                                powerControlGPIOName,
581                                powerGoodGPIOName,
582                                std::move(rails)};
583 
584         device.powerOn();
585         ADD_FAILURE() << "Should not have reached this line.";
586     }
587     catch (const std::exception& e)
588     {
589         EXPECT_STREQ(e.what(), "Device not open: xyz_pseq");
590     }
591 
592     // Test where works
593     {
594         std::string name{"xyz_pseq"};
595         uint8_t bus{0};
596         uint16_t address{0x23};
597         std::string powerControlGPIOName{"power-on"};
598         std::string powerGoodGPIOName{"chassis-pgood"};
599         std::vector<std::unique_ptr<Rail>> rails{};
600         BasicDeviceImpl device{name,
601                                bus,
602                                address,
603                                powerControlGPIOName,
604                                powerGoodGPIOName,
605                                std::move(rails)};
606 
607         MockServices services;
608         device.open(services);
609         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerControlGPIO());
610         EXPECT_CALL(gpio, requestWrite(1)).Times(1);
611         EXPECT_CALL(gpio, setValue(1)).Times(1);
612         EXPECT_CALL(gpio, release()).Times(1);
613         device.powerOn();
614     }
615 
616     // Test where fails: GPIO request throws exception
617     try
618     {
619         std::string name{"xyz_pseq"};
620         uint8_t bus{0};
621         uint16_t address{0x23};
622         std::string powerControlGPIOName{"power-on"};
623         std::string powerGoodGPIOName{"chassis-pgood"};
624         std::vector<std::unique_ptr<Rail>> rails{};
625         BasicDeviceImpl device{name,
626                                bus,
627                                address,
628                                powerControlGPIOName,
629                                powerGoodGPIOName,
630                                std::move(rails)};
631 
632         MockServices services;
633         device.open(services);
634         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerControlGPIO());
635         EXPECT_CALL(gpio, requestWrite(1))
636             .Times(1)
637             .WillOnce(Throw(std::runtime_error{"Unable to write GPIO"}));
638         device.powerOn();
639         ADD_FAILURE() << "Should not have reached this line.";
640     }
641     catch (const std::exception& e)
642     {
643         EXPECT_STREQ(e.what(), "Unable to write GPIO");
644     }
645 }
646 
TEST(BasicDeviceTests,PowerOff)647 TEST(BasicDeviceTests, PowerOff)
648 {
649     // Test where fails: Device not open
650     try
651     {
652         std::string name{"xyz_pseq"};
653         uint8_t bus{0};
654         uint16_t address{0x23};
655         std::string powerControlGPIOName{"power-on"};
656         std::string powerGoodGPIOName{"chassis-pgood"};
657         std::vector<std::unique_ptr<Rail>> rails{};
658         BasicDeviceImpl device{name,
659                                bus,
660                                address,
661                                powerControlGPIOName,
662                                powerGoodGPIOName,
663                                std::move(rails)};
664 
665         device.powerOff();
666         ADD_FAILURE() << "Should not have reached this line.";
667     }
668     catch (const std::exception& e)
669     {
670         EXPECT_STREQ(e.what(), "Device not open: xyz_pseq");
671     }
672 
673     // Test where works
674     {
675         std::string name{"xyz_pseq"};
676         uint8_t bus{0};
677         uint16_t address{0x23};
678         std::string powerControlGPIOName{"power-on"};
679         std::string powerGoodGPIOName{"chassis-pgood"};
680         std::vector<std::unique_ptr<Rail>> rails{};
681         BasicDeviceImpl device{name,
682                                bus,
683                                address,
684                                powerControlGPIOName,
685                                powerGoodGPIOName,
686                                std::move(rails)};
687 
688         MockServices services;
689         device.open(services);
690         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerControlGPIO());
691         EXPECT_CALL(gpio, requestWrite(0)).Times(1);
692         EXPECT_CALL(gpio, setValue(0)).Times(1);
693         EXPECT_CALL(gpio, release()).Times(1);
694         device.powerOff();
695     }
696 
697     // Test where fails: GPIO set value throws exception
698     try
699     {
700         std::string name{"xyz_pseq"};
701         uint8_t bus{0};
702         uint16_t address{0x23};
703         std::string powerControlGPIOName{"power-on"};
704         std::string powerGoodGPIOName{"chassis-pgood"};
705         std::vector<std::unique_ptr<Rail>> rails{};
706         BasicDeviceImpl device{name,
707                                bus,
708                                address,
709                                powerControlGPIOName,
710                                powerGoodGPIOName,
711                                std::move(rails)};
712 
713         MockServices services;
714         device.open(services);
715         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerControlGPIO());
716         EXPECT_CALL(gpio, requestWrite(0)).Times(1);
717         EXPECT_CALL(gpio, setValue(0))
718             .Times(1)
719             .WillOnce(Throw(std::runtime_error{"Unable to write GPIO"}));
720         device.powerOff();
721         ADD_FAILURE() << "Should not have reached this line.";
722     }
723     catch (const std::exception& e)
724     {
725         EXPECT_STREQ(e.what(), "Unable to write GPIO");
726     }
727 }
728 
TEST(BasicDeviceTests,GetPowerGood)729 TEST(BasicDeviceTests, GetPowerGood)
730 {
731     // Test where fails: Device not open
732     try
733     {
734         std::string name{"xyz_pseq"};
735         uint8_t bus{0};
736         uint16_t address{0x23};
737         std::string powerControlGPIOName{"power-on"};
738         std::string powerGoodGPIOName{"chassis-pgood"};
739         std::vector<std::unique_ptr<Rail>> rails{};
740         BasicDeviceImpl device{name,
741                                bus,
742                                address,
743                                powerControlGPIOName,
744                                powerGoodGPIOName,
745                                std::move(rails)};
746 
747         device.getPowerGood();
748         ADD_FAILURE() << "Should not have reached this line.";
749     }
750     catch (const std::exception& e)
751     {
752         EXPECT_STREQ(e.what(), "Device not open: xyz_pseq");
753     }
754 
755     // Test where works: Value is false
756     {
757         std::string name{"xyz_pseq"};
758         uint8_t bus{0};
759         uint16_t address{0x23};
760         std::string powerControlGPIOName{"power-on"};
761         std::string powerGoodGPIOName{"chassis-pgood"};
762         std::vector<std::unique_ptr<Rail>> rails{};
763         BasicDeviceImpl device{name,
764                                bus,
765                                address,
766                                powerControlGPIOName,
767                                powerGoodGPIOName,
768                                std::move(rails)};
769 
770         MockServices services;
771         device.open(services);
772         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
773         EXPECT_CALL(gpio, getValue()).Times(1).WillOnce(Return(0));
774         EXPECT_FALSE(device.getPowerGood());
775     }
776 
777     // Test where works: Value is true
778     {
779         std::string name{"xyz_pseq"};
780         uint8_t bus{0};
781         uint16_t address{0x23};
782         std::string powerControlGPIOName{"power-on"};
783         std::string powerGoodGPIOName{"chassis-pgood"};
784         std::vector<std::unique_ptr<Rail>> rails{};
785         BasicDeviceImpl device{name,
786                                bus,
787                                address,
788                                powerControlGPIOName,
789                                powerGoodGPIOName,
790                                std::move(rails)};
791 
792         MockServices services;
793         device.open(services);
794         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
795         EXPECT_CALL(gpio, getValue()).Times(1).WillOnce(Return(1));
796         EXPECT_TRUE(device.getPowerGood());
797     }
798 
799     // Test where fails: GPIO get value throws exception
800     try
801     {
802         std::string name{"xyz_pseq"};
803         uint8_t bus{0};
804         uint16_t address{0x23};
805         std::string powerControlGPIOName{"power-on"};
806         std::string powerGoodGPIOName{"chassis-pgood"};
807         std::vector<std::unique_ptr<Rail>> rails{};
808         BasicDeviceImpl device{name,
809                                bus,
810                                address,
811                                powerControlGPIOName,
812                                powerGoodGPIOName,
813                                std::move(rails)};
814 
815         MockServices services;
816         device.open(services);
817         MockGPIO& gpio = static_cast<MockGPIO&>(device.getPowerGoodGPIO());
818         EXPECT_CALL(gpio, getValue())
819             .Times(1)
820             .WillOnce(Throw(std::runtime_error{"Unable to read GPIO"}));
821         device.getPowerGood();
822         ADD_FAILURE() << "Should not have reached this line.";
823     }
824     catch (const std::exception& e)
825     {
826         EXPECT_STREQ(e.what(), "Unable to read GPIO");
827     }
828 }
829