1 #include "physical.hpp" 2 3 #include <sys/param.h> 4 5 #include <sdbusplus/bus.hpp> 6 7 #include <gmock/gmock.h> 8 #include <gtest/gtest.h> 9 10 constexpr auto LED_OBJ = "/foo/bar/led"; 11 12 using Action = sdbusplus::xyz::openbmc_project::Led::server::Physical::Action; 13 namespace fs = std::experimental::filesystem; 14 15 fs::path create_sandbox() 16 { 17 /* If your tests need to touch the filesystem, always use mkdtemp() or 18 * mkstemp() for creating directories and files. Tests can be run in 19 * parallel with `make -j`, and if use the same path in multiple tests they 20 * will stomp on eachother and likely fail. 21 */ 22 static constexpr auto tmplt = "/tmp/MockLed.XXXXXX"; 23 char buffer[MAXPATHLEN] = {0}; 24 25 strncpy(buffer, tmplt, sizeof(buffer) - 1); 26 auto dir = mkdtemp(buffer); 27 if (!dir) 28 { 29 throw std::system_error(errno, std::system_category()); 30 } 31 32 /* We want to limit behaviours to mocks, and if methods aren't mocked they 33 * may fall back to their base class implementation. Stop read/write to 34 * directory to prevent streams from creating files. 35 */ 36 if (chmod(dir, S_IXUSR | S_IXGRP) == -1) 37 { 38 throw std::system_error(errno, std::system_category()); 39 } 40 41 return fs::path(dir); 42 } 43 44 class MockLed : public phosphor::led::SysfsLed 45 { 46 public: 47 /* Use a no-args ctor here to avoid headaches with {Nice,Strict}Mock */ 48 MockLed() : SysfsLed(create_sandbox()) 49 {} 50 51 virtual ~MockLed() 52 { 53 chmod(root.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); 54 fs::remove_all(root); 55 } 56 57 MOCK_METHOD0(getBrightness, unsigned long()); 58 MOCK_METHOD1(setBrightness, void(unsigned long value)); 59 MOCK_METHOD0(getMaxBrightness, unsigned long()); 60 MOCK_METHOD0(getTrigger, std::string()); 61 MOCK_METHOD1(setTrigger, void(const std::string& trigger)); 62 MOCK_METHOD0(getDelayOn, unsigned long()); 63 MOCK_METHOD1(setDelayOn, void(unsigned long ms)); 64 MOCK_METHOD0(getDelayOff, unsigned long()); 65 MOCK_METHOD1(setDelayOff, void(unsigned long ms)); 66 }; 67 68 using ::testing::InSequence; 69 using ::testing::NiceMock; 70 using ::testing::Return; 71 using ::testing::Throw; 72 73 TEST(Physical, ctor_none_trigger) 74 { 75 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 76 /* NiceMock ignores calls to methods with no expectations defined */ 77 NiceMock<MockLed> led; 78 ON_CALL(led, getTrigger()).WillByDefault(Return("none")); 79 phosphor::led::Physical phy(bus, LED_OBJ, led); 80 } 81 82 TEST(Physical, ctor_timer_trigger) 83 { 84 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 85 NiceMock<MockLed> led; 86 EXPECT_CALL(led, getTrigger()).WillOnce(Return("timer")); 87 EXPECT_CALL(led, getDelayOn()).WillOnce(Return(500)); 88 EXPECT_CALL(led, getDelayOff()).WillOnce(Return(500)); 89 phosphor::led::Physical phy(bus, LED_OBJ, led); 90 } 91 92 TEST(Physical, off) 93 { 94 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 95 NiceMock<MockLed> led; 96 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(127)); 97 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 98 EXPECT_CALL(led, getBrightness()).WillOnce(Return(phosphor::led::DEASSERT)); 99 EXPECT_CALL(led, setBrightness(phosphor::led::DEASSERT)).Times(0); 100 phosphor::led::Physical phy(bus, LED_OBJ, led); 101 phy.state(Action::Off); 102 } 103 104 TEST(Physical, on) 105 { 106 constexpr unsigned long asserted = 127; 107 108 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 109 NiceMock<MockLed> led; 110 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 111 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 112 EXPECT_CALL(led, setTrigger("none")); 113 EXPECT_CALL(led, setBrightness(asserted)); 114 phosphor::led::Physical phy(bus, LED_OBJ, led); 115 phy.state(Action::On); 116 } 117 118 TEST(Physical, blink) 119 { 120 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 121 NiceMock<MockLed> led; 122 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 123 EXPECT_CALL(led, setTrigger("timer")); 124 EXPECT_CALL(led, setDelayOn(500)); 125 EXPECT_CALL(led, setDelayOff(500)); 126 phosphor::led::Physical phy(bus, LED_OBJ, led); 127 phy.state(Action::Blink); 128 } 129 130 TEST(Physical, ctor_none_trigger_asserted_brightness) 131 { 132 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 133 NiceMock<MockLed> led; 134 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 135 EXPECT_CALL(led, getBrightness()).WillRepeatedly(Return(127)); 136 phosphor::led::Physical phy(bus, LED_OBJ, led); 137 } 138 139 TEST(Physical, on_to_off) 140 { 141 InSequence s; 142 constexpr unsigned long asserted = 127; 143 144 auto bus = sdbusplus::bus::new_default(); 145 NiceMock<MockLed> led; 146 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 147 EXPECT_CALL(led, getTrigger()).Times(1).WillOnce(Return("none")); 148 constexpr auto deasserted = phosphor::led::DEASSERT; 149 EXPECT_CALL(led, getBrightness()).WillOnce(Return(deasserted)); 150 EXPECT_CALL(led, setBrightness(asserted)); 151 EXPECT_CALL(led, setBrightness(deasserted)); 152 phosphor::led::Physical phy(bus, LED_OBJ, led); 153 phy.state(Action::On); 154 phy.state(Action::Off); 155 } 156