blob: ce1f01710e425b3dacb5661c7d2d6e1615d68a88 [file] [log] [blame]
James Feist75eb7692019-02-25 12:50:02 -08001#include "conf.hpp"
Patrick Venture0ef1faf2018-06-13 12:50:53 -07002#include "dbus/dbuspassive.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07003#include "test/dbushelper_mock.hpp"
Patrick Venture0ef1faf2018-06-13 12:50:53 -07004
Patrick Venture0ef1faf2018-06-13 12:50:53 -07005#include <sdbusplus/test/sdbus_mock.hpp>
Patrick Venturea83a3ec2020-08-04 09:52:05 -07006
7#include <functional>
Patrick Venture8729eb92020-08-10 10:38:44 -07008#include <memory>
Patrick Venture0ef1faf2018-06-13 12:50:53 -07009#include <string>
James Feist1f802f52019-02-08 13:51:43 -080010#include <variant>
Patrick Venture0ef1faf2018-06-13 12:50:53 -070011
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070012#include <gmock/gmock.h>
13#include <gtest/gtest.h>
Patrick Venture0ef1faf2018-06-13 12:50:53 -070014
Patrick Venturea0764872020-08-08 07:48:43 -070015namespace pid_control
16{
17namespace
18{
19
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070020using ::testing::_;
Patrick Venture0ef1faf2018-06-13 12:50:53 -070021using ::testing::InSequence;
22using ::testing::Invoke;
23using ::testing::IsNull;
24using ::testing::NotNull;
25using ::testing::Return;
26using ::testing::StrEq;
Patrick Venture0ef1faf2018-06-13 12:50:53 -070027
28std::string SensorIntf = "xyz.openbmc_project.Sensor.Value";
29
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070030TEST(DbusPassiveTest, FactoryFailsWithInvalidType)
31{
Patrick Venture0ef1faf2018-06-13 12:50:53 -070032 // Verify the type is checked by the factory.
33
34 sdbusplus::SdBusMock sdbus_mock;
35 auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock);
36 std::string type = "invalid";
37 std::string id = "id";
38
Patrick Venture8729eb92020-08-10 10:38:44 -070039 auto helper = std::make_unique<DbusHelperMock>();
James Feistf81f2882019-02-26 11:26:36 -080040 auto info = conf::SensorConfig();
Patrick Venture0ef1faf2018-06-13 12:50:53 -070041
James Feist98b704e2019-06-03 16:24:53 -070042 std::unique_ptr<ReadInterface> ri = DbusPassive::createDbusPassive(
Patrick Venture8729eb92020-08-10 10:38:44 -070043 bus_mock, type, id, std::move(helper), &info, nullptr);
Patrick Venture0ef1faf2018-06-13 12:50:53 -070044
45 EXPECT_EQ(ri, nullptr);
46}
47
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070048TEST(DbusPassiveTest, BoringConstructorTest)
49{
Patrick Venturef8cb4642018-10-30 12:02:53 -070050 // Simply build the object, does no error checking.
Patrick Venture0ef1faf2018-06-13 12:50:53 -070051
52 sdbusplus::SdBusMock sdbus_mock;
53 auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock);
54 std::string type = "invalid";
55 std::string id = "id";
56 std::string path = "/xyz/openbmc_project/sensors/unknown/id";
57
Patrick Venture8729eb92020-08-10 10:38:44 -070058 auto helper = std::make_unique<DbusHelperMock>();
Patrick Venture1df9e872020-10-08 15:35:01 -070059 SensorProperties properties;
Patrick Venture0ef1faf2018-06-13 12:50:53 -070060
Patrick Venture8729eb92020-08-10 10:38:44 -070061 DbusPassive(bus_mock, type, id, std::move(helper), properties, false, path,
62 nullptr);
Patrick Venture0ef1faf2018-06-13 12:50:53 -070063 // Success
64}
65
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070066class DbusPassiveTestObj : public ::testing::Test
67{
68 protected:
69 DbusPassiveTestObj() :
70 sdbus_mock(),
Patrick Venture8729eb92020-08-10 10:38:44 -070071 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))),
72 helper(std::make_unique<DbusHelperMock>())
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070073 {
Patrick Venture9b936922020-08-10 11:28:39 -070074 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path)))
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070075 .WillOnce(Return("asdf"));
Patrick Venture0ef1faf2018-06-13 12:50:53 -070076
Patrick Venture8729eb92020-08-10 10:38:44 -070077 EXPECT_CALL(*helper,
Patrick Venture9b936922020-08-10 11:28:39 -070078 getProperties(StrEq("asdf"), StrEq(path), NotNull()))
79 .WillOnce(
80 Invoke([&](const std::string& service, const std::string& path,
Patrick Venture1df9e872020-10-08 15:35:01 -070081 SensorProperties* prop) {
Patrick Venture0ef1faf2018-06-13 12:50:53 -070082 prop->scale = _scale;
83 prop->value = _value;
84 prop->unit = "x";
Patrick Venture6b9f5992019-09-10 09:18:28 -070085 prop->min = 0;
86 prop->max = 0;
Alex.Song8f73ad72021-10-07 00:18:27 +080087 prop->available = true;
Patrick Venture0ef1faf2018-06-13 12:50:53 -070088 }));
Patrick Venture9b936922020-08-10 11:28:39 -070089 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path)))
James Feist36b7d8e2018-10-05 15:39:01 -070090 .WillOnce(Return(false));
Patrick Venture0ef1faf2018-06-13 12:50:53 -070091
James Feistf81f2882019-02-26 11:26:36 -080092 auto info = conf::SensorConfig();
Alex.Song8f73ad72021-10-07 00:18:27 +080093 info.unavailableAsFailed = true;
Patrick Venture8729eb92020-08-10 10:38:44 -070094 ri = DbusPassive::createDbusPassive(bus_mock, type, id,
95 std::move(helper), &info, nullptr);
Patrick Venturee2ec0f62018-09-04 12:30:27 -070096 passive = reinterpret_cast<DbusPassive*>(ri.get());
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070097 EXPECT_FALSE(passive == nullptr);
98 }
Patrick Venture0ef1faf2018-06-13 12:50:53 -070099
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700100 sdbusplus::SdBusMock sdbus_mock;
101 sdbusplus::bus::bus bus_mock;
Patrick Venture8729eb92020-08-10 10:38:44 -0700102 std::unique_ptr<DbusHelperMock> helper;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700103 std::string type = "temp";
104 std::string id = "id";
105 std::string path = "/xyz/openbmc_project/sensors/temperature/id";
106 int64_t _scale = -3;
107 int64_t _value = 10;
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700108
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700109 std::unique_ptr<ReadInterface> ri;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700110 DbusPassive* passive;
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700111};
112
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700113TEST_F(DbusPassiveTestObj, ReadReturnsExpectedValues)
114{
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700115 // Verify read is returning the values.
116 ReadReturn v;
117 v.value = 0.01;
118 // TODO: updated is set when the value is created, so we can range check
119 // it.
120 ReadReturn r = passive->read();
121 EXPECT_EQ(v.value, r.value);
122}
123
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700124TEST_F(DbusPassiveTestObj, SetValueUpdatesValue)
125{
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700126 // Verify setvalue does as advertised.
127
128 double value = 0.01;
129 passive->setValue(value);
130
131 // TODO: updated is set when the value is set, so we can range check it.
132 ReadReturn r = passive->read();
133 EXPECT_EQ(value, r.value);
134}
135
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700136TEST_F(DbusPassiveTestObj, GetScaleReturnsExpectedValue)
137{
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700138 // Verify the scale is returned as expected.
139 EXPECT_EQ(_scale, passive->getScale());
140}
141
Patrick Venture563a3562018-10-30 09:31:26 -0700142TEST_F(DbusPassiveTestObj, getIDReturnsExpectedValue)
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700143{
Patrick Venture563a3562018-10-30 09:31:26 -0700144 // Verify getID returns the expected value.
145 EXPECT_EQ(id, passive->getID());
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700146}
147
Patrick Venture6b9f5992019-09-10 09:18:28 -0700148TEST_F(DbusPassiveTestObj, GetMinValueReturnsExpectedValue)
149{
150 EXPECT_DOUBLE_EQ(0, passive->getMin());
151}
152
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700153TEST_F(DbusPassiveTestObj, VerifyHandlesDbusSignal)
154{
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700155 // The dbus passive sensor listens for updates and if it's the Value
156 // property, it needs to handle it.
157
158 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
159 .WillOnce(Return(nullptr));
160 sdbusplus::message::message msg(nullptr, &sdbus_mock);
161
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700162 const char* Value = "Value";
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700163 int64_t xValue = 10000;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700164 const char* intf = "xyz.openbmc_project.Sensor.Value";
James Feist1f802f52019-02-08 13:51:43 -0800165 // string, std::map<std::string, std::variant<int64_t>>
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700166 // msg.read(msgSensor, msgData);
167
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700168 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700169 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
170 const char** s = static_cast<const char**>(p);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700171 // Read the first parameter, the string.
172 *s = intf;
173 return 0;
174 }))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700175 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
176 const char** s = static_cast<const char**>(p);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700177 *s = Value;
178 // Read the string in the pair (dictionary).
179 return 0;
180 }));
181
182 // std::map
183 EXPECT_CALL(sdbus_mock,
184 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
185 .WillOnce(Return(0));
186
187 // while !at_end()
188 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
189 .WillOnce(Return(0))
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700190 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700191
192 // std::pair
193 EXPECT_CALL(sdbus_mock,
194 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
195 .WillOnce(Return(0));
196
197 EXPECT_CALL(sdbus_mock,
198 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
199 .WillOnce(Return(1));
200 EXPECT_CALL(sdbus_mock,
201 sd_bus_message_enter_container(IsNull(), 'v', StrEq("x")))
202 .WillOnce(Return(0));
203
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700204 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'x', NotNull()))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700205 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
206 int64_t* s = static_cast<int64_t*>(p);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700207 *s = xValue;
208 return 0;
209 }));
210
211 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
212 .WillOnce(Return(0)) /* variant. */
213 .WillOnce(Return(0)) /* std::pair */
214 .WillOnce(Return(0)); /* std::map */
215
Patrick Venture7af157b2018-10-30 11:24:40 -0700216 int rv = handleSensorValue(msg, passive);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700217 EXPECT_EQ(rv, 0); // It's always 0.
218
219 ReadReturn r = passive->read();
220 EXPECT_EQ(10, r.value);
221}
222
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700223TEST_F(DbusPassiveTestObj, VerifyIgnoresOtherPropertySignal)
224{
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700225 // The dbus passive sensor listens for updates and if it's the Value
226 // property, it needs to handle it. In this case, it won't be.
227
228 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
229 .WillOnce(Return(nullptr));
230 sdbusplus::message::message msg(nullptr, &sdbus_mock);
231
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700232 const char* Scale = "Scale";
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700233 int64_t xScale = -6;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700234 const char* intf = "xyz.openbmc_project.Sensor.Value";
James Feist1f802f52019-02-08 13:51:43 -0800235 // string, std::map<std::string, std::variant<int64_t>>
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700236 // msg.read(msgSensor, msgData);
237
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700238 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700239 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
240 const char** s = static_cast<const char**>(p);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700241 // Read the first parameter, the string.
242 *s = intf;
243 return 0;
244 }))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700245 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
246 const char** s = static_cast<const char**>(p);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700247 *s = Scale;
248 // Read the string in the pair (dictionary).
249 return 0;
250 }));
251
252 // std::map
253 EXPECT_CALL(sdbus_mock,
254 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
255 .WillOnce(Return(0));
256
257 // while !at_end()
258 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
259 .WillOnce(Return(0))
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700260 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700261
262 // std::pair
263 EXPECT_CALL(sdbus_mock,
264 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
265 .WillOnce(Return(0));
266
267 EXPECT_CALL(sdbus_mock,
268 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
269 .WillOnce(Return(1));
270 EXPECT_CALL(sdbus_mock,
271 sd_bus_message_enter_container(IsNull(), 'v', StrEq("x")))
272 .WillOnce(Return(0));
273
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700274 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'x', NotNull()))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700275 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
276 int64_t* s = static_cast<int64_t*>(p);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700277 *s = xScale;
278 return 0;
279 }));
280
281 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
282 .WillOnce(Return(0)) /* variant. */
283 .WillOnce(Return(0)) /* std::pair */
284 .WillOnce(Return(0)); /* std::map */
285
Patrick Venture7af157b2018-10-30 11:24:40 -0700286 int rv = handleSensorValue(msg, passive);
Patrick Venture0ef1faf2018-06-13 12:50:53 -0700287 EXPECT_EQ(rv, 0); // It's always 0.
288
289 ReadReturn r = passive->read();
290 EXPECT_EQ(0.01, r.value);
291}
Alex.Song8f73ad72021-10-07 00:18:27 +0800292
James Feist36b7d8e2018-10-05 15:39:01 -0700293TEST_F(DbusPassiveTestObj, VerifyCriticalThresholdAssert)
294{
295
296 // Verifies when a threshold is crossed the sensor goes into error state
297 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
298 .WillOnce(Return(nullptr));
299 sdbusplus::message::message msg(nullptr, &sdbus_mock);
300
301 const char* criticalAlarm = "CriticalAlarmHigh";
302 bool alarm = true;
303 const char* intf = "xyz.openbmc_project.Sensor.Threshold.Critical";
304
305 passive->setFailed(false);
306
307 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
308 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
309 const char** s = static_cast<const char**>(p);
310 // Read the first parameter, the string.
311 *s = intf;
312 return 0;
313 }))
314 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
315 const char** s = static_cast<const char**>(p);
316 *s = criticalAlarm;
317 // Read the string in the pair (dictionary).
318 return 0;
319 }));
320
321 // std::map
322 EXPECT_CALL(sdbus_mock,
323 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
324 .WillOnce(Return(0));
325
326 // while !at_end()
327 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
328 .WillOnce(Return(0))
329 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
330
331 // std::pair
332 EXPECT_CALL(sdbus_mock,
333 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
334 .WillOnce(Return(0));
335
336 EXPECT_CALL(sdbus_mock,
337 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
338 .WillOnce(Return(0));
339 EXPECT_CALL(sdbus_mock,
340 sd_bus_message_verify_type(IsNull(), 'v', StrEq("d")))
341 .WillOnce(Return(0));
342 EXPECT_CALL(sdbus_mock,
343 sd_bus_message_verify_type(IsNull(), 'v', StrEq("b")))
344 .WillOnce(Return(1));
345 EXPECT_CALL(sdbus_mock,
346 sd_bus_message_enter_container(IsNull(), 'v', StrEq("b")))
347 .WillOnce(Return(0));
348
349 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'b', NotNull()))
350 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
351 bool* s = static_cast<bool*>(p);
352 *s = alarm;
353 return 0;
354 }));
355
356 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
357 .WillOnce(Return(0)) /* variant. */
358 .WillOnce(Return(0)) /* std::pair */
359 .WillOnce(Return(0)); /* std::map */
360
Patrick Venture7af157b2018-10-30 11:24:40 -0700361 int rv = handleSensorValue(msg, passive);
James Feist36b7d8e2018-10-05 15:39:01 -0700362 EXPECT_EQ(rv, 0); // It's always 0.
363 bool failed = passive->getFailed();
364 EXPECT_EQ(failed, true);
365}
366
367TEST_F(DbusPassiveTestObj, VerifyCriticalThresholdDeassert)
368{
369
370 // Verifies when a threshold is deasserted a failed sensor goes back into
371 // the normal state
372 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
373 .WillOnce(Return(nullptr));
374 sdbusplus::message::message msg(nullptr, &sdbus_mock);
375
376 const char* criticalAlarm = "CriticalAlarmHigh";
377 bool alarm = false;
378 const char* intf = "xyz.openbmc_project.Sensor.Threshold.Critical";
379
380 passive->setFailed(true);
381
382 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
383 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
384 const char** s = static_cast<const char**>(p);
385 // Read the first parameter, the string.
386 *s = intf;
387 return 0;
388 }))
389 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
390 const char** s = static_cast<const char**>(p);
391 *s = criticalAlarm;
392 // Read the string in the pair (dictionary).
393 return 0;
394 }));
395
396 // std::map
397 EXPECT_CALL(sdbus_mock,
398 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
399 .WillOnce(Return(0));
400
401 // while !at_end()
402 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
403 .WillOnce(Return(0))
404 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
405
406 // std::pair
407 EXPECT_CALL(sdbus_mock,
408 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
409 .WillOnce(Return(0));
410
411 EXPECT_CALL(sdbus_mock,
412 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
413 .WillOnce(Return(0));
414 EXPECT_CALL(sdbus_mock,
415 sd_bus_message_verify_type(IsNull(), 'v', StrEq("d")))
416 .WillOnce(Return(0));
417 EXPECT_CALL(sdbus_mock,
418 sd_bus_message_verify_type(IsNull(), 'v', StrEq("b")))
419 .WillOnce(Return(1));
420 EXPECT_CALL(sdbus_mock,
421 sd_bus_message_enter_container(IsNull(), 'v', StrEq("b")))
422 .WillOnce(Return(0));
423
424 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'b', NotNull()))
425 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
426 bool* s = static_cast<bool*>(p);
427 *s = alarm;
428 return 0;
429 }));
430
431 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
432 .WillOnce(Return(0)) /* variant. */
433 .WillOnce(Return(0)) /* std::pair */
434 .WillOnce(Return(0)); /* std::map */
435
Patrick Venture7af157b2018-10-30 11:24:40 -0700436 int rv = handleSensorValue(msg, passive);
James Feist36b7d8e2018-10-05 15:39:01 -0700437 EXPECT_EQ(rv, 0); // It's always 0.
438 bool failed = passive->getFailed();
439 EXPECT_EQ(failed, false);
Patrick Venture563a3562018-10-30 09:31:26 -0700440}
Patrick Venture6b9f5992019-09-10 09:18:28 -0700441
Alex.Song8f73ad72021-10-07 00:18:27 +0800442TEST_F(DbusPassiveTestObj, VerifyAvailableDeassert)
443{
444
445 // Verifies when Availble is deasserted && unavailableAsFailed == true,
446 // the sensor goes into error state
447 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
448 .WillOnce(Return(nullptr));
449 sdbusplus::message::message msg(nullptr, &sdbus_mock);
450
451 const char* property = "Available";
452 bool asserted = false;
453 const char* intf = "xyz.openbmc_project.State.Decorator.Availability";
454
455 passive->setAvailable(true);
456
457 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
458 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
459 const char** s = static_cast<const char**>(p);
460 // Read the first parameter, the string.
461 *s = intf;
462 return 0;
463 }))
464 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
465 const char** s = static_cast<const char**>(p);
466 *s = property;
467 // Read the string in the pair (dictionary).
468 return 0;
469 }));
470
471 // std::map
472 EXPECT_CALL(sdbus_mock,
473 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
474 .WillOnce(Return(0));
475
476 // while !at_end()
477 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
478 .WillOnce(Return(0))
479 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
480
481 // std::pair
482 EXPECT_CALL(sdbus_mock,
483 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
484 .WillOnce(Return(0));
485
486 EXPECT_CALL(sdbus_mock,
487 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
488 .WillOnce(Return(0));
489 EXPECT_CALL(sdbus_mock,
490 sd_bus_message_verify_type(IsNull(), 'v', StrEq("d")))
491 .WillOnce(Return(0));
492 EXPECT_CALL(sdbus_mock,
493 sd_bus_message_verify_type(IsNull(), 'v', StrEq("b")))
494 .WillOnce(Return(1));
495 EXPECT_CALL(sdbus_mock,
496 sd_bus_message_enter_container(IsNull(), 'v', StrEq("b")))
497 .WillOnce(Return(0));
498
499 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'b', NotNull()))
500 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
501 bool* s = static_cast<bool*>(p);
502 *s = asserted;
503 return 0;
504 }));
505
506 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
507 .WillOnce(Return(0)) /* variant. */
508 .WillOnce(Return(0)) /* std::pair */
509 .WillOnce(Return(0)); /* std::map */
510
511 int rv = handleSensorValue(msg, passive);
512 EXPECT_EQ(rv, 0); // It's always 0.
513 bool failed = passive->getFailed();
514 EXPECT_EQ(failed, true);
515}
516
517TEST_F(DbusPassiveTestObj, VerifyAvailableAssert)
518{
519
520 // Verifies when Availble is asserted && unavailableAsFailed == true,
521 // an error sensor goes back to normal state
522 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
523 .WillOnce(Return(nullptr));
524 sdbusplus::message::message msg(nullptr, &sdbus_mock);
525
526 const char* property = "Available";
527 bool asserted = true;
528 const char* intf = "xyz.openbmc_project.State.Decorator.Availability";
529
530 passive->setAvailable(false);
531 bool failed = passive->getFailed();
532 EXPECT_EQ(failed, true);
533
534 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
535 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
536 const char** s = static_cast<const char**>(p);
537 // Read the first parameter, the string.
538 *s = intf;
539 return 0;
540 }))
541 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
542 const char** s = static_cast<const char**>(p);
543 *s = property;
544 // Read the string in the pair (dictionary).
545 return 0;
546 }));
547
548 // std::map
549 EXPECT_CALL(sdbus_mock,
550 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
551 .WillOnce(Return(0));
552
553 // while !at_end()
554 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
555 .WillOnce(Return(0))
556 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
557
558 // std::pair
559 EXPECT_CALL(sdbus_mock,
560 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
561 .WillOnce(Return(0));
562
563 EXPECT_CALL(sdbus_mock,
564 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
565 .WillOnce(Return(0));
566 EXPECT_CALL(sdbus_mock,
567 sd_bus_message_verify_type(IsNull(), 'v', StrEq("d")))
568 .WillOnce(Return(0));
569 EXPECT_CALL(sdbus_mock,
570 sd_bus_message_verify_type(IsNull(), 'v', StrEq("b")))
571 .WillOnce(Return(1));
572 EXPECT_CALL(sdbus_mock,
573 sd_bus_message_enter_container(IsNull(), 'v', StrEq("b")))
574 .WillOnce(Return(0));
575
576 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'b', NotNull()))
577 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
578 bool* s = static_cast<bool*>(p);
579 *s = asserted;
580 return 0;
581 }));
582
583 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
584 .WillOnce(Return(0)) /* variant. */
585 .WillOnce(Return(0)) /* std::pair */
586 .WillOnce(Return(0)); /* std::map */
587
588 int rv = handleSensorValue(msg, passive);
589 EXPECT_EQ(rv, 0); // It's always 0.
590 failed = passive->getFailed();
591 EXPECT_EQ(failed, false);
592}
593
594class DbusPassiveTestUnaSensorNotAsFailedObj : public ::testing::Test
595{
596 protected:
597 DbusPassiveTestUnaSensorNotAsFailedObj() :
598 sdbus_mock(),
599 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))),
600 helper(std::make_unique<DbusHelperMock>())
601 {
602 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path)))
603 .WillOnce(Return("asdf"));
604
605 EXPECT_CALL(*helper,
606 getProperties(StrEq("asdf"), StrEq(path), NotNull()))
607 .WillOnce(
608 Invoke([&](const std::string& service, const std::string& path,
609 SensorProperties* prop) {
610 prop->scale = _scale;
611 prop->value = _value;
612 prop->unit = "x";
613 prop->min = 0;
614 prop->max = 0;
615 prop->available = true;
616 }));
617 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path)))
618 .WillOnce(Return(false));
619
620 auto info = conf::SensorConfig();
621 info.unavailableAsFailed = false;
622 ri = DbusPassive::createDbusPassive(bus_mock, type, id,
623 std::move(helper), &info, nullptr);
624 passive = reinterpret_cast<DbusPassive*>(ri.get());
625 EXPECT_FALSE(passive == nullptr);
626 }
627
628 sdbusplus::SdBusMock sdbus_mock;
629 sdbusplus::bus::bus bus_mock;
630 std::unique_ptr<DbusHelperMock> helper;
631 std::string type = "temp";
632 std::string id = "id";
633 std::string path = "/xyz/openbmc_project/sensors/temperature/id";
634 int64_t _scale = -3;
635 int64_t _value = 10;
636
637 std::unique_ptr<ReadInterface> ri;
638 DbusPassive* passive;
639};
640
641TEST_F(DbusPassiveTestUnaSensorNotAsFailedObj, VerifyAvailableDeassert)
642{
643
644 // Verifies when Availble is deasserted && unavailableAsFailed == false,
645 // the sensor remains at OK state but reading goes to NaN.
646 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
647 .WillOnce(Return(nullptr));
648 sdbusplus::message::message msg(nullptr, &sdbus_mock);
649
650 const char* property = "Available";
651 bool asserted = false;
652 const char* intf = "xyz.openbmc_project.State.Decorator.Availability";
653
654 passive->setAvailable(true);
655
656 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
657 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
658 const char** s = static_cast<const char**>(p);
659 // Read the first parameter, the string.
660 *s = intf;
661 return 0;
662 }))
663 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
664 const char** s = static_cast<const char**>(p);
665 *s = property;
666 // Read the string in the pair (dictionary).
667 return 0;
668 }));
669
670 // std::map
671 EXPECT_CALL(sdbus_mock,
672 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
673 .WillOnce(Return(0));
674
675 // while !at_end()
676 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
677 .WillOnce(Return(0))
678 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
679
680 // std::pair
681 EXPECT_CALL(sdbus_mock,
682 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
683 .WillOnce(Return(0));
684
685 EXPECT_CALL(sdbus_mock,
686 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
687 .WillOnce(Return(0));
688 EXPECT_CALL(sdbus_mock,
689 sd_bus_message_verify_type(IsNull(), 'v', StrEq("d")))
690 .WillOnce(Return(0));
691 EXPECT_CALL(sdbus_mock,
692 sd_bus_message_verify_type(IsNull(), 'v', StrEq("b")))
693 .WillOnce(Return(1));
694 EXPECT_CALL(sdbus_mock,
695 sd_bus_message_enter_container(IsNull(), 'v', StrEq("b")))
696 .WillOnce(Return(0));
697
698 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'b', NotNull()))
699 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
700 bool* s = static_cast<bool*>(p);
701 *s = asserted;
702 return 0;
703 }));
704
705 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
706 .WillOnce(Return(0)) /* variant. */
707 .WillOnce(Return(0)) /* std::pair */
708 .WillOnce(Return(0)); /* std::map */
709
710 int rv = handleSensorValue(msg, passive);
711 EXPECT_EQ(rv, 0); // It's always 0.
712 bool failed = passive->getFailed();
713 EXPECT_EQ(failed, false);
714 ReadReturn r = passive->read();
715 EXPECT_FALSE(std::isfinite(r.value));
716}
717
718TEST_F(DbusPassiveTestUnaSensorNotAsFailedObj, VerifyAvailableAssert)
719{
720
721 // Verifies when a sensor's state goes from unavailble to available
722 // && unavailableAsFailed == false, this sensor remains at OK state.
723 EXPECT_CALL(sdbus_mock, sd_bus_message_ref(IsNull()))
724 .WillOnce(Return(nullptr));
725 sdbusplus::message::message msg(nullptr, &sdbus_mock);
726
727 const char* property = "Available";
728 bool asserted = true;
729 const char* intf = "xyz.openbmc_project.State.Decorator.Availability";
730
731 passive->setAvailable(false);
732 bool failed = passive->getFailed();
733 EXPECT_EQ(failed, false);
734
735 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull()))
736 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
737 const char** s = static_cast<const char**>(p);
738 // Read the first parameter, the string.
739 *s = intf;
740 return 0;
741 }))
742 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
743 const char** s = static_cast<const char**>(p);
744 *s = property;
745 // Read the string in the pair (dictionary).
746 return 0;
747 }));
748
749 // std::map
750 EXPECT_CALL(sdbus_mock,
751 sd_bus_message_enter_container(IsNull(), 'a', StrEq("{sv}")))
752 .WillOnce(Return(0));
753
754 // while !at_end()
755 EXPECT_CALL(sdbus_mock, sd_bus_message_at_end(IsNull(), 0))
756 .WillOnce(Return(0))
757 .WillOnce(Return(1)); // So it exits the loop after reading one pair.
758
759 // std::pair
760 EXPECT_CALL(sdbus_mock,
761 sd_bus_message_enter_container(IsNull(), 'e', StrEq("sv")))
762 .WillOnce(Return(0));
763
764 EXPECT_CALL(sdbus_mock,
765 sd_bus_message_verify_type(IsNull(), 'v', StrEq("x")))
766 .WillOnce(Return(0));
767 EXPECT_CALL(sdbus_mock,
768 sd_bus_message_verify_type(IsNull(), 'v', StrEq("d")))
769 .WillOnce(Return(0));
770 EXPECT_CALL(sdbus_mock,
771 sd_bus_message_verify_type(IsNull(), 'v', StrEq("b")))
772 .WillOnce(Return(1));
773 EXPECT_CALL(sdbus_mock,
774 sd_bus_message_enter_container(IsNull(), 'v', StrEq("b")))
775 .WillOnce(Return(0));
776
777 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'b', NotNull()))
778 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) {
779 bool* s = static_cast<bool*>(p);
780 *s = asserted;
781 return 0;
782 }));
783
784 EXPECT_CALL(sdbus_mock, sd_bus_message_exit_container(IsNull()))
785 .WillOnce(Return(0)) /* variant. */
786 .WillOnce(Return(0)) /* std::pair */
787 .WillOnce(Return(0)); /* std::map */
788
789 int rv = handleSensorValue(msg, passive);
790 EXPECT_EQ(rv, 0); // It's always 0.
791 failed = passive->getFailed();
792 EXPECT_EQ(failed, false);
793}
794
Patrick Venture9b936922020-08-10 11:28:39 -0700795void GetPropertiesMax3k(const std::string& service, const std::string& path,
796 SensorProperties* prop)
Patrick Venture6b9f5992019-09-10 09:18:28 -0700797{
798 prop->scale = -3;
799 prop->value = 10;
800 prop->unit = "x";
801 prop->min = 0;
802 prop->max = 3000;
803}
804
Patrick Venture9b936922020-08-10 11:28:39 -0700805using GetPropertiesFunction = std::function<void(
806 const std::string&, const std::string&, SensorProperties*)>;
Patrick Venture6b9f5992019-09-10 09:18:28 -0700807
808// TODO: There is definitely a cleaner way to do this.
809class DbusPassiveTest3kMaxObj : public ::testing::Test
810{
811 protected:
812 DbusPassiveTest3kMaxObj() :
813 sdbus_mock(),
Patrick Venture8729eb92020-08-10 10:38:44 -0700814 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))),
815 helper(std::make_unique<DbusHelperMock>())
Patrick Venture6b9f5992019-09-10 09:18:28 -0700816 {
Patrick Venture9b936922020-08-10 11:28:39 -0700817 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path)))
Patrick Venture6b9f5992019-09-10 09:18:28 -0700818 .WillOnce(Return("asdf"));
819
Patrick Venture8729eb92020-08-10 10:38:44 -0700820 EXPECT_CALL(*helper,
Patrick Venture9b936922020-08-10 11:28:39 -0700821 getProperties(StrEq("asdf"), StrEq(path), NotNull()))
Patrick Venture6b9f5992019-09-10 09:18:28 -0700822 .WillOnce(_getProps);
Patrick Venture9b936922020-08-10 11:28:39 -0700823 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path)))
Patrick Venture6b9f5992019-09-10 09:18:28 -0700824 .WillOnce(Return(false));
825
826 auto info = conf::SensorConfig();
Patrick Venture8729eb92020-08-10 10:38:44 -0700827 ri = DbusPassive::createDbusPassive(bus_mock, type, id,
828 std::move(helper), &info, nullptr);
Patrick Venture6b9f5992019-09-10 09:18:28 -0700829 passive = reinterpret_cast<DbusPassive*>(ri.get());
830 EXPECT_FALSE(passive == nullptr);
831 }
832
833 sdbusplus::SdBusMock sdbus_mock;
834 sdbusplus::bus::bus bus_mock;
Patrick Venture8729eb92020-08-10 10:38:44 -0700835 std::unique_ptr<DbusHelperMock> helper;
Patrick Venture6b9f5992019-09-10 09:18:28 -0700836 std::string type = "temp";
837 std::string id = "id";
838 std::string path = "/xyz/openbmc_project/sensors/temperature/id";
839 int64_t _scale = -3;
840 int64_t _value = 10;
841
842 std::unique_ptr<ReadInterface> ri;
843 DbusPassive* passive;
844 GetPropertiesFunction _getProps = &GetPropertiesMax3k;
845};
846
847TEST_F(DbusPassiveTest3kMaxObj, ReadMinAndMaxReturnsExpected)
848{
849 EXPECT_DOUBLE_EQ(0, passive->getMin());
850 EXPECT_DOUBLE_EQ(3, passive->getMax());
851}
852
853class DbusPassiveTest3kMaxIgnoredObj : public ::testing::Test
854{
855 protected:
856 DbusPassiveTest3kMaxIgnoredObj() :
857 sdbus_mock(),
Patrick Venture8729eb92020-08-10 10:38:44 -0700858 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))),
859 helper(std::make_unique<DbusHelperMock>())
Patrick Venture6b9f5992019-09-10 09:18:28 -0700860 {
Patrick Venture9b936922020-08-10 11:28:39 -0700861 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path)))
Patrick Venture6b9f5992019-09-10 09:18:28 -0700862 .WillOnce(Return("asdf"));
863
Patrick Venture8729eb92020-08-10 10:38:44 -0700864 EXPECT_CALL(*helper,
Patrick Venture9b936922020-08-10 11:28:39 -0700865 getProperties(StrEq("asdf"), StrEq(path), NotNull()))
Patrick Venture6b9f5992019-09-10 09:18:28 -0700866 .WillOnce(_getProps);
Patrick Venture9b936922020-08-10 11:28:39 -0700867 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path)))
Patrick Venture6b9f5992019-09-10 09:18:28 -0700868 .WillOnce(Return(false));
869
870 auto info = conf::SensorConfig();
871 info.ignoreDbusMinMax = true;
Patrick Venture8729eb92020-08-10 10:38:44 -0700872 ri = DbusPassive::createDbusPassive(bus_mock, type, id,
873 std::move(helper), &info, nullptr);
Patrick Venture6b9f5992019-09-10 09:18:28 -0700874 passive = reinterpret_cast<DbusPassive*>(ri.get());
875 EXPECT_FALSE(passive == nullptr);
876 }
877
878 sdbusplus::SdBusMock sdbus_mock;
879 sdbusplus::bus::bus bus_mock;
Patrick Venture8729eb92020-08-10 10:38:44 -0700880 std::unique_ptr<DbusHelperMock> helper;
Patrick Venture6b9f5992019-09-10 09:18:28 -0700881 std::string type = "temp";
882 std::string id = "id";
883 std::string path = "/xyz/openbmc_project/sensors/temperature/id";
884 int64_t _scale = -3;
885 int64_t _value = 10;
886
887 std::unique_ptr<ReadInterface> ri;
888 DbusPassive* passive;
889 GetPropertiesFunction _getProps = &GetPropertiesMax3k;
890};
891
892TEST_F(DbusPassiveTest3kMaxIgnoredObj, ReadMinAndMaxReturnsExpected)
893{
894 EXPECT_DOUBLE_EQ(0, passive->getMin());
895 EXPECT_DOUBLE_EQ(0, passive->getMax());
896}
Patrick Venturea0764872020-08-08 07:48:43 -0700897
898} // namespace
899} // namespace pid_control