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