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