1 #include "conf.hpp" 2 #include "dbus/dbuspassive.hpp" 3 #include "test/dbushelper_mock.hpp" 4 5 #include <sdbusplus/test/sdbus_mock.hpp> 6 7 #include <functional> 8 #include <memory> 9 #include <string> 10 #include <variant> 11 12 #include <gmock/gmock.h> 13 #include <gtest/gtest.h> 14 15 namespace pid_control 16 { 17 namespace 18 { 19 20 using ::testing::_; 21 using ::testing::InSequence; 22 using ::testing::Invoke; 23 using ::testing::IsNull; 24 using ::testing::NotNull; 25 using ::testing::Return; 26 using ::testing::StrEq; 27 28 std::string SensorIntf = "xyz.openbmc_project.Sensor.Value"; 29 30 TEST(DbusPassiveTest, FactoryFailsWithInvalidType) 31 { 32 // 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 39 auto helper = std::make_unique<DbusHelperMock>(); 40 auto info = conf::SensorConfig(); 41 42 std::unique_ptr<ReadInterface> ri = DbusPassive::createDbusPassive( 43 bus_mock, type, id, std::move(helper), &info, nullptr); 44 45 EXPECT_EQ(ri, nullptr); 46 } 47 48 TEST(DbusPassiveTest, BoringConstructorTest) 49 { 50 // Simply build the object, does no error checking. 51 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 58 auto helper = std::make_unique<DbusHelperMock>(); 59 SensorProperties properties; 60 61 DbusPassive(bus_mock, type, id, std::move(helper), properties, false, path, 62 nullptr); 63 // Success 64 } 65 66 class DbusPassiveTestObj : public ::testing::Test 67 { 68 protected: 69 DbusPassiveTestObj() : 70 sdbus_mock(), 71 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))), 72 helper(std::make_unique<DbusHelperMock>()) 73 { 74 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path))) 75 .WillOnce(Return("asdf")); 76 77 EXPECT_CALL(*helper, 78 getProperties(StrEq("asdf"), StrEq(path), NotNull())) 79 .WillOnce( 80 Invoke([&](const std::string& service, const std::string& path, 81 SensorProperties* prop) { 82 prop->scale = _scale; 83 prop->value = _value; 84 prop->unit = "x"; 85 prop->min = 0; 86 prop->max = 0; 87 prop->available = true; 88 })); 89 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path))) 90 .WillOnce(Return(false)); 91 92 auto info = conf::SensorConfig(); 93 info.unavailableAsFailed = true; 94 ri = DbusPassive::createDbusPassive(bus_mock, type, id, 95 std::move(helper), &info, nullptr); 96 passive = reinterpret_cast<DbusPassive*>(ri.get()); 97 EXPECT_FALSE(passive == nullptr); 98 } 99 100 sdbusplus::SdBusMock sdbus_mock; 101 sdbusplus::bus::bus bus_mock; 102 std::unique_ptr<DbusHelperMock> helper; 103 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; 108 109 std::unique_ptr<ReadInterface> ri; 110 DbusPassive* passive; 111 }; 112 113 TEST_F(DbusPassiveTestObj, ReadReturnsExpectedValues) 114 { 115 // 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 124 TEST_F(DbusPassiveTestObj, SetValueUpdatesValue) 125 { 126 // 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 136 TEST_F(DbusPassiveTestObj, GetScaleReturnsExpectedValue) 137 { 138 // Verify the scale is returned as expected. 139 EXPECT_EQ(_scale, passive->getScale()); 140 } 141 142 TEST_F(DbusPassiveTestObj, getIDReturnsExpectedValue) 143 { 144 // Verify getID returns the expected value. 145 EXPECT_EQ(id, passive->getID()); 146 } 147 148 TEST_F(DbusPassiveTestObj, GetMinValueReturnsExpectedValue) 149 { 150 EXPECT_DOUBLE_EQ(0, passive->getMin()); 151 } 152 153 TEST_F(DbusPassiveTestObj, VerifyHandlesDbusSignal) 154 { 155 // 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 162 const char* Value = "Value"; 163 int64_t xValue = 10000; 164 const char* intf = "xyz.openbmc_project.Sensor.Value"; 165 // string, std::map<std::string, std::variant<int64_t>> 166 // msg.read(msgSensor, msgData); 167 168 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull())) 169 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 170 const char** s = static_cast<const char**>(p); 171 // Read the first parameter, the string. 172 *s = intf; 173 return 0; 174 })) 175 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 176 const char** s = static_cast<const char**>(p); 177 *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)) 190 .WillOnce(Return(1)); // So it exits the loop after reading one pair. 191 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 204 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'x', NotNull())) 205 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 206 int64_t* s = static_cast<int64_t*>(p); 207 *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 216 int rv = handleSensorValue(msg, passive); 217 EXPECT_EQ(rv, 0); // It's always 0. 218 219 ReadReturn r = passive->read(); 220 EXPECT_EQ(10, r.value); 221 } 222 223 TEST_F(DbusPassiveTestObj, VerifyIgnoresOtherPropertySignal) 224 { 225 // 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 232 const char* Scale = "Scale"; 233 int64_t xScale = -6; 234 const char* intf = "xyz.openbmc_project.Sensor.Value"; 235 // string, std::map<std::string, std::variant<int64_t>> 236 // msg.read(msgSensor, msgData); 237 238 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 's', NotNull())) 239 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 240 const char** s = static_cast<const char**>(p); 241 // Read the first parameter, the string. 242 *s = intf; 243 return 0; 244 })) 245 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 246 const char** s = static_cast<const char**>(p); 247 *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)) 260 .WillOnce(Return(1)); // So it exits the loop after reading one pair. 261 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 274 EXPECT_CALL(sdbus_mock, sd_bus_message_read_basic(IsNull(), 'x', NotNull())) 275 .WillOnce(Invoke([&](sd_bus_message* m, char type, void* p) { 276 int64_t* s = static_cast<int64_t*>(p); 277 *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 286 int rv = handleSensorValue(msg, passive); 287 EXPECT_EQ(rv, 0); // It's always 0. 288 289 ReadReturn r = passive->read(); 290 EXPECT_EQ(0.01, r.value); 291 } 292 293 TEST_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 361 int rv = handleSensorValue(msg, passive); 362 EXPECT_EQ(rv, 0); // It's always 0. 363 bool failed = passive->getFailed(); 364 EXPECT_EQ(failed, true); 365 } 366 367 TEST_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 436 int rv = handleSensorValue(msg, passive); 437 EXPECT_EQ(rv, 0); // It's always 0. 438 bool failed = passive->getFailed(); 439 EXPECT_EQ(failed, false); 440 } 441 442 TEST_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 517 TEST_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 594 class 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 641 TEST_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 718 TEST_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 795 void GetPropertiesMax3k(const std::string& service, const std::string& path, 796 SensorProperties* prop) 797 { 798 prop->scale = -3; 799 prop->value = 10; 800 prop->unit = "x"; 801 prop->min = 0; 802 prop->max = 3000; 803 } 804 805 using GetPropertiesFunction = std::function<void( 806 const std::string&, const std::string&, SensorProperties*)>; 807 808 // TODO: There is definitely a cleaner way to do this. 809 class DbusPassiveTest3kMaxObj : public ::testing::Test 810 { 811 protected: 812 DbusPassiveTest3kMaxObj() : 813 sdbus_mock(), 814 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))), 815 helper(std::make_unique<DbusHelperMock>()) 816 { 817 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path))) 818 .WillOnce(Return("asdf")); 819 820 EXPECT_CALL(*helper, 821 getProperties(StrEq("asdf"), StrEq(path), NotNull())) 822 .WillOnce(_getProps); 823 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path))) 824 .WillOnce(Return(false)); 825 826 auto info = conf::SensorConfig(); 827 ri = DbusPassive::createDbusPassive(bus_mock, type, id, 828 std::move(helper), &info, nullptr); 829 passive = reinterpret_cast<DbusPassive*>(ri.get()); 830 EXPECT_FALSE(passive == nullptr); 831 } 832 833 sdbusplus::SdBusMock sdbus_mock; 834 sdbusplus::bus::bus bus_mock; 835 std::unique_ptr<DbusHelperMock> helper; 836 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 847 TEST_F(DbusPassiveTest3kMaxObj, ReadMinAndMaxReturnsExpected) 848 { 849 EXPECT_DOUBLE_EQ(0, passive->getMin()); 850 EXPECT_DOUBLE_EQ(3, passive->getMax()); 851 } 852 853 class DbusPassiveTest3kMaxIgnoredObj : public ::testing::Test 854 { 855 protected: 856 DbusPassiveTest3kMaxIgnoredObj() : 857 sdbus_mock(), 858 bus_mock(std::move(sdbusplus::get_mocked_new(&sdbus_mock))), 859 helper(std::make_unique<DbusHelperMock>()) 860 { 861 EXPECT_CALL(*helper, getService(StrEq(SensorIntf), StrEq(path))) 862 .WillOnce(Return("asdf")); 863 864 EXPECT_CALL(*helper, 865 getProperties(StrEq("asdf"), StrEq(path), NotNull())) 866 .WillOnce(_getProps); 867 EXPECT_CALL(*helper, thresholdsAsserted(StrEq("asdf"), StrEq(path))) 868 .WillOnce(Return(false)); 869 870 auto info = conf::SensorConfig(); 871 info.ignoreDbusMinMax = true; 872 ri = DbusPassive::createDbusPassive(bus_mock, type, id, 873 std::move(helper), &info, nullptr); 874 passive = reinterpret_cast<DbusPassive*>(ri.get()); 875 EXPECT_FALSE(passive == nullptr); 876 } 877 878 sdbusplus::SdBusMock sdbus_mock; 879 sdbusplus::bus::bus bus_mock; 880 std::unique_ptr<DbusHelperMock> helper; 881 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 892 TEST_F(DbusPassiveTest3kMaxIgnoredObj, ReadMinAndMaxReturnsExpected) 893 { 894 EXPECT_DOUBLE_EQ(0, passive->getMin()); 895 EXPECT_DOUBLE_EQ(0, passive->getMax()); 896 } 897 898 } // namespace 899 } // namespace pid_control 900