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 52 virtual ~MockLed() 53 { 54 chmod(root.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); 55 fs::remove_all(root); 56 } 57 58 MOCK_METHOD0(getBrightness, unsigned long()); 59 MOCK_METHOD1(setBrightness, void(unsigned long value)); 60 MOCK_METHOD0(getMaxBrightness, unsigned long()); 61 MOCK_METHOD0(getTrigger, std::string()); 62 MOCK_METHOD1(setTrigger, void(const std::string& trigger)); 63 MOCK_METHOD0(getDelayOn, unsigned long()); 64 MOCK_METHOD1(setDelayOn, void(unsigned long ms)); 65 MOCK_METHOD0(getDelayOff, unsigned long()); 66 MOCK_METHOD1(setDelayOff, void(unsigned long ms)); 67 }; 68 69 using ::testing::InSequence; 70 using ::testing::NiceMock; 71 using ::testing::Return; 72 using ::testing::Throw; 73 74 TEST(Physical, ctor_none_trigger) 75 { 76 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 77 /* NiceMock ignores calls to methods with no expectations defined */ 78 NiceMock<MockLed> led; 79 ON_CALL(led, getTrigger()).WillByDefault(Return("none")); 80 phosphor::led::Physical phy(bus, LED_OBJ, led); 81 } 82 83 TEST(Physical, ctor_timer_trigger) 84 { 85 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 86 NiceMock<MockLed> led; 87 EXPECT_CALL(led, getTrigger()).WillOnce(Return("timer")); 88 EXPECT_CALL(led, getDelayOn()).WillOnce(Return(500)); 89 EXPECT_CALL(led, getDelayOff()).WillOnce(Return(500)); 90 phosphor::led::Physical phy(bus, LED_OBJ, led); 91 } 92 93 TEST(Physical, off) 94 { 95 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 96 NiceMock<MockLed> led; 97 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(127)); 98 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 99 EXPECT_CALL(led, getBrightness()).WillOnce(Return(phosphor::led::DEASSERT)); 100 EXPECT_CALL(led, setBrightness(phosphor::led::DEASSERT)).Times(0); 101 phosphor::led::Physical phy(bus, LED_OBJ, led); 102 phy.state(Action::Off); 103 } 104 105 TEST(Physical, on) 106 { 107 constexpr unsigned long asserted = 127; 108 109 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 110 NiceMock<MockLed> led; 111 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 112 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 113 EXPECT_CALL(led, setTrigger("none")); 114 EXPECT_CALL(led, setBrightness(asserted)); 115 phosphor::led::Physical phy(bus, LED_OBJ, led); 116 phy.state(Action::On); 117 } 118 119 TEST(Physical, blink) 120 { 121 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 122 NiceMock<MockLed> led; 123 EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); 124 EXPECT_CALL(led, setTrigger("timer")); 125 EXPECT_CALL(led, setDelayOn(500)); 126 EXPECT_CALL(led, setDelayOff(500)); 127 phosphor::led::Physical phy(bus, LED_OBJ, led); 128 phy.state(Action::Blink); 129 } 130 131 TEST(Physical, ctor_none_trigger_asserted_brightness) 132 { 133 sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); 134 NiceMock<MockLed> led; 135 EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); 136 EXPECT_CALL(led, getBrightness()).WillRepeatedly(Return(127)); 137 phosphor::led::Physical phy(bus, LED_OBJ, led); 138 } 139 140 TEST(Physical, on_to_off) 141 { 142 InSequence s; 143 constexpr unsigned long asserted = 127; 144 145 auto bus = sdbusplus::bus::new_default(); 146 NiceMock<MockLed> led; 147 ON_CALL(led, getMaxBrightness()).WillByDefault(Return(asserted)); 148 EXPECT_CALL(led, getTrigger()).Times(1).WillOnce(Return("none")); 149 constexpr auto deasserted = phosphor::led::DEASSERT; 150 EXPECT_CALL(led, getBrightness()).WillOnce(Return(deasserted)); 151 EXPECT_CALL(led, setBrightness(asserted)); 152 EXPECT_CALL(led, setBrightness(deasserted)); 153 phosphor::led::Physical phy(bus, LED_OBJ, led); 154 phy.state(Action::On); 155 phy.state(Action::Off); 156 } 157