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
createSandbox()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 */
MockLed()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
~MockLed()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
TEST(Physical,ctor_none_trigger)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
TEST(Physical,ctor_maxbrightness_and_brightness_read_127)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
TEST(Physical,ctor_maxbrightness_and_brightness_read_0)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
TEST(Physical,ctor_only_maxbrightness_read_127)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
TEST(Physical,ctor_only_brightness_read_127)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
TEST(Physical,ctor_timer_trigger)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
TEST(Physical,off)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
TEST(Physical,on)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
TEST(Physical,blink)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
TEST(Physical,ctor_none_trigger_asserted_brightness)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
TEST(Physical,on_to_off)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