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::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_t 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 EXPECT_EQ(phy.state(), Action::Off); 81 } 82 83 TEST(Physical, ctor_maxbrightness_and_brightness_read_127) 84 { 85 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 86 /* NiceMock ignores calls to methods with no expectations defined */ 87 NiceMock<MockLed> led; 88 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 89 EXPECT_CALL(led, getBrightness()).WillOnce(Return(127)); 90 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(127)); 91 phosphor::led::Physical phy(bus, LED_OBJ, led); 92 EXPECT_EQ(phy.state(), Action::On); 93 } 94 95 TEST(Physical, ctor_maxbrightness_and_brightness_read_0) 96 { 97 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 98 /* NiceMock ignores calls to methods with no expectations defined */ 99 NiceMock<MockLed> led; 100 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 101 EXPECT_CALL(led, getBrightness()).WillOnce(Return(0)); 102 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(0)); 103 phosphor::led::Physical phy(bus, LED_OBJ, led); 104 EXPECT_EQ(phy.state(), Action::Off); 105 } 106 107 TEST(Physical, ctor_only_maxbrightness_read_127) 108 { 109 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 110 /* NiceMock ignores calls to methods with no expectations defined */ 111 NiceMock<MockLed> led; 112 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 113 EXPECT_CALL(led, getBrightness()).WillOnce(Return(0)); 114 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(127)); 115 phosphor::led::Physical phy(bus, LED_OBJ, led); 116 EXPECT_EQ(phy.state(), Action::Off); 117 } 118 119 TEST(Physical, ctor_only_brightness_read_127) 120 { 121 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 122 /* NiceMock ignores calls to methods with no expectations defined */ 123 NiceMock<MockLed> led; 124 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 125 EXPECT_CALL(led, getBrightness()).WillOnce(Return(127)); 126 EXPECT_CALL(led, getMaxBrightness()).WillOnce(Return(0)); 127 phosphor::led::Physical phy(bus, LED_OBJ, led); 128 EXPECT_EQ(phy.state(), Action::Off); 129 } 130 131 TEST(Physical, ctor_timer_trigger) 132 { 133 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 134 NiceMock<MockLed> led; 135 EXPECT_CALL(led, getTrigger()).WillOnce(Return("timer")); 136 EXPECT_CALL(led, getDelayOn()).WillOnce(Return(500)); 137 EXPECT_CALL(led, getDelayOff()).WillOnce(Return(500)); 138 phosphor::led::Physical phy(bus, LED_OBJ, led); 139 EXPECT_EQ(phy.state(), Action::Off); 140 } 141 142 TEST(Physical, off) 143 { 144 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 145 NiceMock<MockLed> led; 146 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(127)); 147 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 148 EXPECT_CALL(led, getBrightness()).WillOnce(Return(phosphor::led::DEASSERT)); 149 EXPECT_CALL(led, setBrightness(phosphor::led::DEASSERT)).Times(0); 150 phosphor::led::Physical phy(bus, LED_OBJ, led); 151 phy.state(Action::Off); 152 EXPECT_EQ(phy.state(), Action::Off); 153 } 154 155 TEST(Physical, on) 156 { 157 constexpr unsigned long asserted = 127; 158 159 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 160 NiceMock<MockLed> led; 161 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 162 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 163 EXPECT_CALL(led, setTrigger("none")); 164 EXPECT_CALL(led, setBrightness(asserted)); 165 phosphor::led::Physical phy(bus, LED_OBJ, led); 166 phy.state(Action::On); 167 EXPECT_EQ(phy.state(), Action::On); 168 } 169 170 TEST(Physical, blink) 171 { 172 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 173 NiceMock<MockLed> led; 174 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 175 EXPECT_CALL(led, setTrigger("timer")); 176 EXPECT_CALL(led, setDelayOn(500)); 177 EXPECT_CALL(led, setDelayOff(500)); 178 phosphor::led::Physical phy(bus, LED_OBJ, led); 179 phy.state(Action::Blink); 180 EXPECT_EQ(phy.state(), Action::Blink); 181 } 182 183 TEST(Physical, ctor_none_trigger_asserted_brightness) 184 { 185 sdbusplus::bus_t bus = sdbusplus::bus::new_default(); 186 NiceMock<MockLed> led; 187 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 188 EXPECT_CALL(led, getBrightness()).WillRepeatedly(Return(127)); 189 phosphor::led::Physical phy(bus, LED_OBJ, led); 190 EXPECT_EQ(phy.state(), Action::Off); 191 } 192 193 TEST(Physical, on_to_off) 194 { 195 InSequence s; 196 constexpr unsigned long asserted = 127; 197 198 auto bus = sdbusplus::bus::new_default(); 199 NiceMock<MockLed> led; 200 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 201 EXPECT_CALL(led, getTrigger()).Times(1).WillOnce(Return("none")); 202 constexpr auto deasserted = phosphor::led::DEASSERT; 203 EXPECT_CALL(led, getBrightness()).WillOnce(Return(deasserted)); 204 EXPECT_CALL(led, setBrightness(asserted)); 205 EXPECT_CALL(led, setBrightness(deasserted)); 206 phosphor::led::Physical phy(bus, LED_OBJ, led); 207 phy.state(Action::On); 208 EXPECT_EQ(phy.state(), Action::On); 209 phy.state(Action::Off); 210 EXPECT_EQ(phy.state(), Action::Off); 211 } 212