#include "physical.hpp" #include #include #include #include constexpr auto LED_OBJ = "/foo/bar/led"; using Action = sdbusplus::xyz::openbmc_project::Led::server::Physical::Action; namespace fs = std::experimental::filesystem; fs::path create_sandbox() { /* If your tests need to touch the filesystem, always use mkdtemp() or * mkstemp() for creating directories and files. Tests can be run in * parallel with `make -j`, and if use the same path in multiple tests they * will stomp on eachother and likely fail. */ static constexpr auto tmplt = "/tmp/MockLed.XXXXXX"; char buffer[MAXPATHLEN] = {0}; strncpy(buffer, tmplt, sizeof(buffer) - 1); auto dir = mkdtemp(buffer); if (!dir) { throw std::system_error(errno, std::system_category()); } /* We want to limit behaviours to mocks, and if methods aren't mocked they * may fall back to their base class implementation. Stop read/write to * directory to prevent streams from creating files. */ if (chmod(dir, S_IXUSR | S_IXGRP) == -1) { throw std::system_error(errno, std::system_category()); } return fs::path(dir); } class MockLed : public phosphor::led::SysfsLed { public: /* Use a no-args ctor here to avoid headaches with {Nice,Strict}Mock */ MockLed() : SysfsLed(create_sandbox()) { } virtual ~MockLed() { chmod(root.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); fs::remove_all(root); } MOCK_METHOD0(getBrightness, unsigned long()); MOCK_METHOD1(setBrightness, void(unsigned long value)); MOCK_METHOD0(getMaxBrightness, unsigned long()); MOCK_METHOD0(getTrigger, std::string()); MOCK_METHOD1(setTrigger, void(const std::string& trigger)); MOCK_METHOD0(getDelayOn, unsigned long()); MOCK_METHOD1(setDelayOn, void(unsigned long ms)); MOCK_METHOD0(getDelayOff, unsigned long()); MOCK_METHOD1(setDelayOff, void(unsigned long ms)); }; using ::testing::InSequence; using ::testing::NiceMock; using ::testing::Return; using ::testing::Throw; TEST(Physical, ctor_none_trigger) { sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); /* NiceMock ignores calls to methods with no expectations defined */ NiceMock led; ON_CALL(led, getTrigger()).WillByDefault(Return("none")); phosphor::led::Physical phy(bus, LED_OBJ, led); } TEST(Physical, ctor_timer_trigger) { sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); NiceMock led; EXPECT_CALL(led, getTrigger()).WillOnce(Return("timer")); EXPECT_CALL(led, getDelayOn()).WillOnce(Return(500)); EXPECT_CALL(led, getDelayOff()).WillOnce(Return(500)); phosphor::led::Physical phy(bus, LED_OBJ, led); } TEST(Physical, off) { sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); NiceMock led; ON_CALL(led, getTrigger()).WillByDefault(Return("none")); phosphor::led::Physical phy(bus, LED_OBJ, led); phy.state(Action::Off); } TEST(Physical, on) { sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); NiceMock led; ON_CALL(led, getTrigger()).WillByDefault(Return("none")); phosphor::led::Physical phy(bus, LED_OBJ, led); phy.state(Action::On); } TEST(Physical, blink) { sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); NiceMock led; EXPECT_CALL(led, getTrigger()).WillOnce(Return("none")); EXPECT_CALL(led, setTrigger("timer")); EXPECT_CALL(led, setDelayOn(500)); EXPECT_CALL(led, setDelayOff(500)); phosphor::led::Physical phy(bus, LED_OBJ, led); phy.state(Action::Blink); } TEST(Physical, ctor_none_trigger_asserted_brightness) { sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); NiceMock led; EXPECT_CALL(led, getTrigger()).WillRepeatedly(Return("none")); constexpr auto val = phosphor::led::ASSERT; EXPECT_CALL(led, getBrightness()).WillRepeatedly(Return(val)); phosphor::led::Physical phy(bus, LED_OBJ, led); } TEST(Physical, on_to_off) { InSequence s; auto bus = sdbusplus::bus::new_default(); NiceMock led; EXPECT_CALL(led, getTrigger()).Times(1).WillOnce(Return("none")); constexpr auto deasserted = phosphor::led::DEASSERT; EXPECT_CALL(led, getBrightness()).WillOnce(Return(deasserted)); constexpr auto asserted = phosphor::led::ASSERT; EXPECT_CALL(led, setBrightness(asserted)); EXPECT_CALL(led, setBrightness(deasserted)); phosphor::led::Physical phy(bus, LED_OBJ, led); phy.state(Action::On); phy.state(Action::Off); }