1 #include "pid/ec/logging.hpp" 2 #include "pid/ec/pid.hpp" 3 #include "pid/zone.hpp" 4 #include "sensors/manager.hpp" 5 #include "test/controller_mock.hpp" 6 #include "test/helpers.hpp" 7 #include "test/sensor_mock.hpp" 8 9 #include <sdbusplus/test/sdbus_mock.hpp> 10 11 #include <chrono> 12 #include <cstring> 13 #include <vector> 14 15 #include <gmock/gmock.h> 16 #include <gtest/gtest.h> 17 18 namespace pid_control 19 { 20 namespace 21 { 22 23 using ::testing::_; 24 using ::testing::IsNull; 25 using ::testing::Return; 26 using ::testing::StrEq; 27 28 static std::string modeInterface = "xyz.openbmc_project.Control.Mode"; 29 static std::string enableInterface = "xyz.openbmc_project.Object.Enable"; 30 31 namespace 32 { 33 34 TEST(PidZoneConstructorTest, BoringConstructorTest) 35 { 36 // Build a PID Zone. 37 38 sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode, 39 sdbus_mock_enable; 40 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive); 41 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host); 42 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode); 43 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable); 44 45 EXPECT_CALL(sdbus_mock_host, 46 sd_bus_add_object_manager( 47 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors"))) 48 .WillOnce(Return(0)); 49 50 SensorManager m(bus_mock_passive, bus_mock_host); 51 52 bool defer = true; 53 const char* objPath = "/path/"; 54 int64_t zone = 1; 55 double minThermalOutput = 1000.0; 56 double failSafePercent = 0.75; 57 conf::CycleTime cycleTime; 58 59 double d; 60 std::vector<std::string> properties; 61 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, properties, 62 &d); 63 64 std::string sensorname = "temp1"; 65 std::string pidsensorpath = "/xyz/openbmc_project/settings/fanctrl/zone1/" + 66 sensorname; 67 68 double de; 69 std::vector<std::string> propertiesenable; 70 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(), 71 enableInterface, propertiesenable, &de); 72 73 DbusPidZone p(zone, minThermalOutput, failSafePercent, cycleTime, m, 74 bus_mock_mode, objPath, defer); 75 // Success. 76 } 77 78 } // namespace 79 80 class PidZoneTest : public ::testing::Test 81 { 82 protected: 83 PidZoneTest() : 84 property_index(), properties(), sdbus_mock_passive(), sdbus_mock_host(), 85 sdbus_mock_mode(), sdbus_mock_enable() 86 { 87 EXPECT_CALL(sdbus_mock_host, 88 sd_bus_add_object_manager( 89 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors"))) 90 .WillOnce(Return(0)); 91 92 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive); 93 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host); 94 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode); 95 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable); 96 97 // Compiler weirdly not happy about just instantiating mgr(...); 98 SensorManager m(bus_mock_passive, bus_mock_host); 99 mgr = std::move(m); 100 101 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, 102 properties, &property_index); 103 104 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(), 105 enableInterface, propertiesenable, 106 &propertyenable_index); 107 108 zone = std::make_unique<DbusPidZone>(zoneId, minThermalOutput, 109 failSafePercent, cycleTime, mgr, 110 bus_mock_mode, objPath, defer); 111 } 112 113 // unused 114 double property_index; 115 std::vector<std::string> properties; 116 double propertyenable_index; 117 std::vector<std::string> propertiesenable; 118 119 sdbusplus::SdBusMock sdbus_mock_passive; 120 sdbusplus::SdBusMock sdbus_mock_host; 121 sdbusplus::SdBusMock sdbus_mock_mode; 122 sdbusplus::SdBusMock sdbus_mock_enable; 123 int64_t zoneId = 1; 124 double minThermalOutput = 1000.0; 125 double failSafePercent = 0.75; 126 bool defer = true; 127 const char* objPath = "/path/"; 128 SensorManager mgr; 129 conf::CycleTime cycleTime; 130 131 std::string sensorname = "temp1"; 132 std::string pidsensorpath = "/xyz/openbmc_project/settings/fanctrl/zone1/" + 133 sensorname; 134 135 std::unique_ptr<DbusPidZone> zone; 136 }; 137 138 TEST_F(PidZoneTest, GetZoneId_ReturnsExpected) 139 { 140 // Verifies the zoneId returned is what we expect. 141 142 EXPECT_EQ(zoneId, zone->getZoneID()); 143 } 144 145 TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected) 146 { 147 // Verifies that the zone starts in manual mode. Verifies that one can set 148 // the mode. 149 EXPECT_FALSE(zone->getManualMode()); 150 151 zone->setManualMode(true); 152 EXPECT_TRUE(zone->getManualMode()); 153 } 154 155 TEST_F(PidZoneTest, AddPidControlProcessGetAndSetEnableTest_BehavesAsExpected) 156 { 157 // Verifies that the zone starts in enable mode. Verifies that one can set 158 // enable the mode. 159 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable); 160 161 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv( 162 IsNull(), StrEq(pidsensorpath.c_str()), 163 StrEq(enableInterface), NotNull())) 164 .Times(::testing::AnyNumber()) 165 .WillOnce(Invoke( 166 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path, 167 [[maybe_unused]] const char* interface, const char** names) { 168 EXPECT_STREQ("Enable", names[0]); 169 return 0; 170 })); 171 172 zone->addPidControlProcess(sensorname, bus_mock_enable, 173 pidsensorpath.c_str(), defer); 174 EXPECT_TRUE(zone->isPidProcessEnabled(sensorname)); 175 } 176 177 TEST_F(PidZoneTest, SetManualMode_RedundantWritesEnabledOnceAfterManualMode) 178 { 179 // Tests adding a fan PID controller to the zone, and verifies it's 180 // touched during processing. 181 182 std::unique_ptr<PIDController> tpid = 183 std::make_unique<ControllerMock>("fan1", zone.get()); 184 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get()); 185 186 // Access the internal pid configuration to clear it out (unrelated to the 187 // test). 188 ec::pid_info_t* info = tpid->getPIDInfo(); 189 std::memset(info, 0x00, sizeof(ec::pid_info_t)); 190 191 zone->addFanPID(std::move(tpid)); 192 193 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0)); 194 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0)); 195 EXPECT_CALL(*tmock, outputProc(_)); 196 197 // while zone is in auto mode redundant writes should be disabled 198 EXPECT_FALSE(zone->getRedundantWrite()); 199 200 // but switching from manual to auto enables a single redundant write 201 zone->setManualMode(true); 202 zone->setManualMode(false); 203 EXPECT_TRUE(zone->getRedundantWrite()); 204 205 // after one iteration of a pid loop redundant write should be cleared 206 zone->processFans(); 207 EXPECT_FALSE(zone->getRedundantWrite()); 208 } 209 210 TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected) 211 { 212 // Tests addSetPoint, clearSetPoints, determineMaxSetPointRequest 213 // and getMinThermalSetPoint. 214 215 // Need to add pid control process for the zone that can enable 216 // the process and add the set point. 217 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable); 218 219 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv( 220 IsNull(), StrEq(pidsensorpath.c_str()), 221 StrEq(enableInterface), NotNull())) 222 .Times(::testing::AnyNumber()) 223 .WillOnce(Invoke( 224 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path, 225 [[maybe_unused]] const char* interface, const char** names) { 226 EXPECT_STREQ("Enable", names[0]); 227 return 0; 228 })); 229 230 zone->addPidControlProcess(sensorname, bus_mock_enable, 231 pidsensorpath.c_str(), defer); 232 233 // At least one value must be above the minimum thermal setpoint used in 234 // the constructor otherwise it'll choose that value 235 std::vector<double> values = {100, 200, 300, 400, 500, 5000}; 236 237 for (auto v : values) 238 { 239 zone->addSetPoint(v, sensorname); 240 } 241 242 // This will pull the maximum RPM setpoint request. 243 zone->determineMaxSetPointRequest(); 244 EXPECT_EQ(5000, zone->getMaxSetPointRequest()); 245 246 // Clear the values, so it'll choose the minimum thermal setpoint. 247 zone->clearSetPoints(); 248 249 // This will go through the RPM set point values and grab the maximum. 250 zone->determineMaxSetPointRequest(); 251 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest()); 252 } 253 254 TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected) 255 { 256 // Tests adding several RPM setpoints, however, they're all lower than the 257 // configured minimal thermal setpoint RPM value. 258 259 // Need to add pid control process for the zone that can enable 260 // the process and add the set point. 261 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable); 262 263 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv( 264 IsNull(), StrEq(pidsensorpath.c_str()), 265 StrEq(enableInterface), NotNull())) 266 .Times(::testing::AnyNumber()) 267 .WillOnce(Invoke( 268 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path, 269 [[maybe_unused]] const char* interface, const char** names) { 270 EXPECT_STREQ("Enable", names[0]); 271 return 0; 272 })); 273 274 zone->addPidControlProcess(sensorname, bus_mock_enable, 275 pidsensorpath.c_str(), defer); 276 277 std::vector<double> values = {100, 200, 300, 400, 500}; 278 279 for (auto v : values) 280 { 281 zone->addSetPoint(v, sensorname); 282 } 283 284 // This will pull the maximum RPM setpoint request. 285 zone->determineMaxSetPointRequest(); 286 287 // Verifies the value returned in the minimal thermal rpm set point. 288 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest()); 289 } 290 291 TEST_F(PidZoneTest, GetFailSafePercent_ReturnsExpected) 292 { 293 // Verify the value used to create the object is stored. 294 EXPECT_EQ(failSafePercent, zone->getFailSafePercent()); 295 } 296 297 TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors) 298 { 299 // This test will add a couple thermal inputs, and verify that the zone 300 // initializes into failsafe mode, and will read each sensor. 301 302 std::string name1 = "temp1"; 303 int64_t timeout = 1; 304 305 std::unique_ptr<Sensor> sensor1 = std::make_unique<SensorMock>(name1, 306 timeout); 307 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); 308 309 std::string name2 = "temp2"; 310 std::unique_ptr<Sensor> sensor2 = std::make_unique<SensorMock>(name2, 311 timeout); 312 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); 313 314 std::string type = "unchecked"; 315 mgr.addSensor(type, name1, std::move(sensor1)); 316 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); 317 mgr.addSensor(type, name2, std::move(sensor2)); 318 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); 319 320 // Now that the sensors exist, add them to the zone. 321 zone->addThermalInput(name1); 322 zone->addThermalInput(name2); 323 324 // Initialize Zone 325 zone->initializeCache(); 326 327 // Verify now in failsafe mode. 328 EXPECT_TRUE(zone->getFailSafeMode()); 329 330 ReadReturn r1; 331 r1.value = 10.0; 332 r1.updated = std::chrono::high_resolution_clock::now(); 333 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 334 335 ReadReturn r2; 336 r2.value = 11.0; 337 r2.updated = std::chrono::high_resolution_clock::now(); 338 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 339 340 // Read the sensors, this will put the values into the cache. 341 zone->updateSensors(); 342 343 // We should no longer be in failsafe mode. 344 EXPECT_FALSE(zone->getFailSafeMode()); 345 346 EXPECT_EQ(r1.value, zone->getCachedValue(name1)); 347 EXPECT_EQ(r2.value, zone->getCachedValue(name2)); 348 } 349 350 TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached) 351 { 352 // This will add a couple fan inputs, and verify the values are cached. 353 354 std::string name1 = "fan1"; 355 int64_t timeout = 2; 356 357 std::unique_ptr<Sensor> sensor1 = std::make_unique<SensorMock>(name1, 358 timeout); 359 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); 360 361 std::string name2 = "fan2"; 362 std::unique_ptr<Sensor> sensor2 = std::make_unique<SensorMock>(name2, 363 timeout); 364 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); 365 366 std::string type = "unchecked"; 367 mgr.addSensor(type, name1, std::move(sensor1)); 368 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); 369 mgr.addSensor(type, name2, std::move(sensor2)); 370 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); 371 372 // Now that the sensors exist, add them to the zone. 373 zone->addFanInput(name1); 374 zone->addFanInput(name2); 375 376 // Initialize Zone 377 zone->initializeCache(); 378 379 ReadReturn r1; 380 r1.value = 10.0; 381 r1.updated = std::chrono::high_resolution_clock::now(); 382 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 383 384 ReadReturn r2; 385 r2.value = 11.0; 386 r2.updated = std::chrono::high_resolution_clock::now(); 387 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 388 389 // Method under test will read through each fan sensor for the zone and 390 // cache the values. 391 zone->updateFanTelemetry(); 392 393 EXPECT_EQ(r1.value, zone->getCachedValue(name1)); 394 EXPECT_EQ(r2.value, zone->getCachedValue(name2)); 395 } 396 397 TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode) 398 { 399 // On the second updateSensors call, the updated timestamp will be beyond 400 // the timeout limit. 401 402 int64_t timeout = 1; 403 404 std::string name1 = "temp1"; 405 std::unique_ptr<Sensor> sensor1 = std::make_unique<SensorMock>(name1, 406 timeout); 407 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); 408 409 std::string name2 = "temp2"; 410 std::unique_ptr<Sensor> sensor2 = std::make_unique<SensorMock>(name2, 411 timeout); 412 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); 413 414 std::string type = "unchecked"; 415 mgr.addSensor(type, name1, std::move(sensor1)); 416 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); 417 mgr.addSensor(type, name2, std::move(sensor2)); 418 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); 419 420 zone->addThermalInput(name1); 421 zone->addThermalInput(name2); 422 423 // Initialize Zone 424 zone->initializeCache(); 425 426 // Verify now in failsafe mode. 427 EXPECT_TRUE(zone->getFailSafeMode()); 428 429 ReadReturn r1; 430 r1.value = 10.0; 431 r1.updated = std::chrono::high_resolution_clock::now(); 432 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 433 434 ReadReturn r2; 435 r2.value = 11.0; 436 r2.updated = std::chrono::high_resolution_clock::now(); 437 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 438 439 zone->updateSensors(); 440 EXPECT_FALSE(zone->getFailSafeMode()); 441 442 // Ok, so we're not in failsafe mode, so let's set updated to the past. 443 // sensor1 will have an updated field older than its timeout value, but 444 // sensor2 will be fine. :D 445 r1.updated -= std::chrono::seconds(3); 446 r2.updated = std::chrono::high_resolution_clock::now(); 447 448 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 449 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 450 451 // Method under test will read each sensor. One sensor's value is older 452 // than the timeout for that sensor and this triggers failsafe mode. 453 zone->updateSensors(); 454 EXPECT_TRUE(zone->getFailSafeMode()); 455 } 456 457 TEST_F(PidZoneTest, FanInputTest_FailsafeToValid_ReadsSensors) 458 { 459 // This will add a couple fan inputs, and verify the values are cached. 460 461 std::string name1 = "fan1"; 462 int64_t timeout = 2; 463 464 std::unique_ptr<Sensor> sensor1 = std::make_unique<SensorMock>(name1, 465 timeout); 466 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); 467 468 std::string name2 = "fan2"; 469 std::unique_ptr<Sensor> sensor2 = std::make_unique<SensorMock>(name2, 470 timeout); 471 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); 472 473 std::string type = "unchecked"; 474 mgr.addSensor(type, name1, std::move(sensor1)); 475 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); 476 mgr.addSensor(type, name2, std::move(sensor2)); 477 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); 478 479 // Now that the sensors exist, add them to the zone. 480 zone->addFanInput(name1); 481 zone->addFanInput(name2); 482 483 // Initialize Zone 484 zone->initializeCache(); 485 486 // Verify now in failsafe mode. 487 EXPECT_TRUE(zone->getFailSafeMode()); 488 489 ReadReturn r1; 490 r1.value = 10.0; 491 r1.updated = std::chrono::high_resolution_clock::now(); 492 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 493 494 ReadReturn r2; 495 r2.value = 11.0; 496 r2.updated = std::chrono::high_resolution_clock::now(); 497 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 498 499 // Method under test will read through each fan sensor for the zone and 500 // cache the values. 501 zone->updateFanTelemetry(); 502 503 // We should no longer be in failsafe mode. 504 EXPECT_FALSE(zone->getFailSafeMode()); 505 506 EXPECT_EQ(r1.value, zone->getCachedValue(name1)); 507 EXPECT_EQ(r2.value, zone->getCachedValue(name2)); 508 } 509 510 TEST_F(PidZoneTest, FanInputTest_ValueTimeoutEntersFailSafeMode) 511 { 512 // This will add a couple fan inputs, and verify the values are cached. 513 514 std::string name1 = "fan1"; 515 int64_t timeout = 2; 516 517 std::unique_ptr<Sensor> sensor1 = std::make_unique<SensorMock>(name1, 518 timeout); 519 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); 520 521 std::string name2 = "fan2"; 522 std::unique_ptr<Sensor> sensor2 = std::make_unique<SensorMock>(name2, 523 timeout); 524 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get()); 525 526 std::string type = "unchecked"; 527 mgr.addSensor(type, name1, std::move(sensor1)); 528 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); 529 mgr.addSensor(type, name2, std::move(sensor2)); 530 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2); 531 532 // Now that the sensors exist, add them to the zone. 533 zone->addFanInput(name1); 534 zone->addFanInput(name2); 535 536 // Initialize Zone 537 zone->initializeCache(); 538 539 // Verify now in failsafe mode. 540 EXPECT_TRUE(zone->getFailSafeMode()); 541 542 ReadReturn r1; 543 r1.value = 10.0; 544 r1.updated = std::chrono::high_resolution_clock::now(); 545 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 546 547 ReadReturn r2; 548 r2.value = 11.0; 549 r2.updated = std::chrono::high_resolution_clock::now(); 550 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 551 552 // Method under test will read through each fan sensor for the zone and 553 // cache the values. 554 zone->updateFanTelemetry(); 555 556 // We should no longer be in failsafe mode. 557 EXPECT_FALSE(zone->getFailSafeMode()); 558 559 r1.updated -= std::chrono::seconds(3); 560 r2.updated = std::chrono::high_resolution_clock::now(); 561 562 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1)); 563 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2)); 564 565 zone->updateFanTelemetry(); 566 EXPECT_TRUE(zone->getFailSafeMode()); 567 } 568 569 TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected) 570 { 571 // One can grab a sensor from the manager through the zone. 572 573 int64_t timeout = 1; 574 575 std::string name1 = "temp1"; 576 std::unique_ptr<Sensor> sensor1 = std::make_unique<SensorMock>(name1, 577 timeout); 578 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get()); 579 580 std::string type = "unchecked"; 581 mgr.addSensor(type, name1, std::move(sensor1)); 582 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1); 583 584 zone->addThermalInput(name1); 585 586 // Verify method under test returns the pointer we expect. 587 EXPECT_EQ(mgr.getSensor(name1), zone->getSensor(name1)); 588 } 589 590 TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed) 591 { 592 // Tests adding a thermal PID controller to the zone, and verifies it's 593 // touched during processing. 594 595 std::unique_ptr<PIDController> tpid = 596 std::make_unique<ControllerMock>("thermal1", zone.get()); 597 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get()); 598 599 // Access the internal pid configuration to clear it out (unrelated to the 600 // test). 601 ec::pid_info_t* info = tpid->getPIDInfo(); 602 std::memset(info, 0x00, sizeof(ec::pid_info_t)); 603 604 zone->addThermalPID(std::move(tpid)); 605 606 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0)); 607 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0)); 608 EXPECT_CALL(*tmock, outputProc(_)); 609 610 // Method under test will, for each thermal PID, call setpt, input, and 611 // output. 612 zone->processThermals(); 613 } 614 615 TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed) 616 { 617 // Tests adding a fan PID controller to the zone, and verifies it's 618 // touched during processing. 619 620 std::unique_ptr<PIDController> tpid = 621 std::make_unique<ControllerMock>("fan1", zone.get()); 622 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get()); 623 624 // Access the internal pid configuration to clear it out (unrelated to the 625 // test). 626 ec::pid_info_t* info = tpid->getPIDInfo(); 627 std::memset(info, 0x00, sizeof(ec::pid_info_t)); 628 629 zone->addFanPID(std::move(tpid)); 630 631 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0)); 632 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0)); 633 EXPECT_CALL(*tmock, outputProc(_)); 634 635 // Method under test will, for each fan PID, call setpt, input, and output. 636 zone->processFans(); 637 } 638 639 TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected) 640 { 641 // The manual(bool) method is inherited from the dbus mode interface. 642 643 // Verifies that someone doesn't remove the internal call to the dbus 644 // object from which we're inheriting. 645 EXPECT_CALL(sdbus_mock_mode, 646 sd_bus_emit_properties_changed_strv( 647 IsNull(), StrEq(objPath), StrEq(modeInterface), NotNull())) 648 .WillOnce(Invoke( 649 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path, 650 [[maybe_unused]] const char* interface, const char** names) { 651 EXPECT_STREQ("Manual", names[0]); 652 return 0; 653 })); 654 655 // Method under test will set the manual mode to true and broadcast this 656 // change on dbus. 657 zone->manual(true); 658 EXPECT_TRUE(zone->getManualMode()); 659 } 660 661 TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected) 662 { 663 // This property is implemented by us as read-only, such that trying to 664 // write to it will have no effect. 665 EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode()); 666 } 667 668 } // namespace 669 } // namespace pid_control 670