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 ledObj = "/foo/bar/led"; 11 12 using Action = sdbusplus::xyz::openbmc_project::Led::server::Physical::Action; 13 namespace fs = std::filesystem; 14 15 fs::path createSandbox() 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 std::array<char, MAXPATHLEN> buffer = {0}; 24 25 strncpy(buffer.data(), tmplt, buffer.size() - 1); 26 auto* dir = mkdtemp(buffer.data()); 27 if (dir == nullptr) 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 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(createSandbox()) 49 {} 50 MockLed(MockLed& other) = delete; 51 MockLed(MockLed&& other) = delete; 52 MockLed& operator=(MockLed& other) = delete; 53 MockLed&& operator=(MockLed&& other) = delete; 54 55 ~MockLed() override 56 { 57 chmod(root.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); 58 fs::remove_all(root); 59 } 60 61 MOCK_METHOD0(getBrightness, unsigned long()); 62 MOCK_METHOD1(setBrightness, void(unsigned long value)); 63 MOCK_METHOD0(getMaxBrightness, unsigned long()); 64 MOCK_METHOD0(getTrigger, std::string()); 65 MOCK_METHOD1(setTrigger, void(const std::string& trigger)); 66 MOCK_METHOD0(getDelayOn, unsigned long()); 67 MOCK_METHOD1(setDelayOn, void(unsigned long ms)); 68 MOCK_METHOD0(getDelayOff, unsigned long()); 69 MOCK_METHOD1(setDelayOff, void(unsigned long ms)); 70 }; 71 72 using ::testing::InSequence; 73 using ::testing::NiceMock; 74 using ::testing::Return; 75 76 TEST(Physical, ctor_none_trigger) 77 { 78 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 79 /* NiceMock ignores calls to methods with no expectations defined */ 80 NiceMock<MockLed> led; 81 ON_CALL(led, getTrigger()).WillByDefault(Return("none")); 82 phosphor::led::Physical phy(bus, ledObj, led); 83 EXPECT_EQ(phy.state(), Action::Off); 84 } 85 86 TEST(Physical, ctor_maxbrightness_and_brightness_read_127) 87 { 88 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 89 /* NiceMock ignores calls to methods with no expectations defined */ 90 NiceMock<MockLed> led; 91 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 92 EXPECT_CALL(led, getBrightness()).WillOnce(Return(127)); 93 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(127)); 94 phosphor::led::Physical phy(bus, ledObj, led); 95 EXPECT_EQ(phy.state(), Action::On); 96 } 97 98 TEST(Physical, ctor_maxbrightness_and_brightness_read_0) 99 { 100 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 101 /* NiceMock ignores calls to methods with no expectations defined */ 102 NiceMock<MockLed> led; 103 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 104 EXPECT_CALL(led, getBrightness()).WillOnce(Return(0)); 105 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(0)); 106 phosphor::led::Physical phy(bus, ledObj, led); 107 EXPECT_EQ(phy.state(), Action::Off); 108 } 109 110 TEST(Physical, ctor_only_maxbrightness_read_127) 111 { 112 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 113 /* NiceMock ignores calls to methods with no expectations defined */ 114 NiceMock<MockLed> led; 115 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 116 EXPECT_CALL(led, getBrightness()).WillOnce(Return(0)); 117 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(127)); 118 phosphor::led::Physical phy(bus, ledObj, led); 119 EXPECT_EQ(phy.state(), Action::Off); 120 } 121 122 TEST(Physical, ctor_only_brightness_read_127) 123 { 124 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 125 /* NiceMock ignores calls to methods with no expectations defined */ 126 NiceMock<MockLed> led; 127 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 128 EXPECT_CALL(led, getBrightness()).WillOnce(Return(127)); 129 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(0)); 130 phosphor::led::Physical phy(bus, ledObj, led); 131 EXPECT_EQ(phy.state(), Action::Off); 132 } 133 134 TEST(Physical, ctor_timer_trigger) 135 { 136 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 137 NiceMock<MockLed> led; 138 EXPECT_CALL(led, getTrigger()).WillOnce(Return("timer")); 139 EXPECT_CALL(led, getDelayOn()).WillOnce(Return(500)); 140 EXPECT_CALL(led, getDelayOff()).WillOnce(Return(500)); 141 phosphor::led::Physical phy(bus, ledObj, led); 142 EXPECT_EQ(phy.state(), Action::Off); 143 } 144 145 TEST(Physical, off) 146 { 147 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 148 NiceMock<MockLed> led; 149 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(127)); 150 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 151 EXPECT_CALL(led, getBrightness()) 152 .WillOnce(Return(phosphor::led::deasserted)); 153 EXPECT_CALL(led, setBrightness(phosphor::led::deasserted)).Times(0); 154 phosphor::led::Physical phy(bus, ledObj, led); 155 phy.state(Action::Off); 156 EXPECT_EQ(phy.state(), Action::Off); 157 } 158 159 TEST(Physical, on) 160 { 161 constexpr unsigned long asserted = 127; 162 163 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 164 NiceMock<MockLed> led; 165 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 166 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 167 EXPECT_CALL(led, setTrigger("none")); 168 EXPECT_CALL(led, setBrightness(asserted)); 169 phosphor::led::Physical phy(bus, ledObj, led); 170 phy.state(Action::On); 171 EXPECT_EQ(phy.state(), Action::On); 172 } 173 174 TEST(Physical, blink) 175 { 176 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 177 NiceMock<MockLed> led; 178 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 179 EXPECT_CALL(led, setTrigger("timer")); 180 EXPECT_CALL(led, setDelayOn(500)); 181 EXPECT_CALL(led, setDelayOff(500)); 182 phosphor::led::Physical phy(bus, ledObj, led); 183 phy.state(Action::Blink); 184 EXPECT_EQ(phy.state(), Action::Blink); 185 } 186 187 TEST(Physical, ctor_none_trigger_asserted_brightness) 188 { 189 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 190 NiceMock<MockLed> led; 191 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 192 EXPECT_CALL(led, getBrightness()).WillRepeatedly(Return(127)); 193 phosphor::led::Physical phy(bus, ledObj, led); 194 EXPECT_EQ(phy.state(), Action::Off); 195 } 196 197 TEST(Physical, on_to_off) 198 { 199 InSequence s; 200 constexpr unsigned long asserted = 127; 201 202 auto bus = sdbusplus::bus::new_default(); 203 NiceMock<MockLed> led; 204 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 205 EXPECT_CALL(led, getTrigger()).Times(1).WillOnce(Return("none")); 206 constexpr auto deasserted = phosphor::led::deasserted; 207 EXPECT_CALL(led, getBrightness()).WillOnce(Return(deasserted)); 208 EXPECT_CALL(led, setBrightness(asserted)); 209 EXPECT_CALL(led, setBrightness(deasserted)); 210 phosphor::led::Physical phy(bus, ledObj, led); 211 phy.state(Action::On); 212 EXPECT_EQ(phy.state(), Action::On); 213 phy.state(Action::Off); 214 EXPECT_EQ(phy.state(), Action::Off); 215 } 216