blob: 172c818618215ca45d6bf3cf8964c2cbcfd8d6db [file] [log] [blame]
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07001#include "pid/ec/pid.hpp"
Patrick Venturea58197c2018-06-11 15:29:45 -07002#include "pid/zone.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07003#include "sensors/manager.hpp"
4#include "test/controller_mock.hpp"
5#include "test/helpers.hpp"
6#include "test/sensor_mock.hpp"
Patrick Venturea58197c2018-06-11 15:29:45 -07007
Patrick Venturea83a3ec2020-08-04 09:52:05 -07008#include <sdbusplus/test/sdbus_mock.hpp>
9
Patrick Venturea58197c2018-06-11 15:29:45 -070010#include <chrono>
11#include <cstring>
Patrick Venturea58197c2018-06-11 15:29:45 -070012#include <vector>
13
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070014#include <gmock/gmock.h>
15#include <gtest/gtest.h>
Patrick Venturea58197c2018-06-11 15:29:45 -070016
Patrick Venturea0764872020-08-08 07:48:43 -070017namespace pid_control
18{
19namespace
20{
21
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070022using ::testing::_;
Patrick Venturea58197c2018-06-11 15:29:45 -070023using ::testing::IsNull;
24using ::testing::Return;
25using ::testing::StrEq;
Patrick Venturea58197c2018-06-11 15:29:45 -070026
27static std::string modeInterface = "xyz.openbmc_project.Control.Mode";
28
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070029namespace
30{
Patrick Venturea58197c2018-06-11 15:29:45 -070031
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070032TEST(PidZoneConstructorTest, BoringConstructorTest)
33{
Patrick Venturea58197c2018-06-11 15:29:45 -070034 // Build a PID Zone.
35
36 sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode;
37 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
38 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
39 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
40
41 EXPECT_CALL(sdbus_mock_host,
42 sd_bus_add_object_manager(
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070043 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
Patrick Venturea58197c2018-06-11 15:29:45 -070044 .WillOnce(Return(0));
45
James Feist1fe08952019-05-07 09:17:16 -070046 SensorManager m(bus_mock_passive, bus_mock_host);
Patrick Venturea58197c2018-06-11 15:29:45 -070047
48 bool defer = true;
Patrick Venturee2ec0f62018-09-04 12:30:27 -070049 const char* objPath = "/path/";
Patrick Venturea58197c2018-06-11 15:29:45 -070050 int64_t zone = 1;
James Feist3484bed2019-02-25 13:28:18 -080051 double minThermalOutput = 1000.0;
Patrick Venture5f59c0f2018-11-11 12:55:14 -080052 double failSafePercent = 0.75;
Patrick Venturea58197c2018-06-11 15:29:45 -070053
James Feist0709e2f2020-07-08 10:59:45 -070054 double d;
Patrick Venturea58197c2018-06-11 15:29:45 -070055 std::vector<std::string> properties;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070056 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, properties,
James Feist0709e2f2020-07-08 10:59:45 -070057 &d);
Patrick Venturea58197c2018-06-11 15:29:45 -070058
Patrick Venture597ebd62020-08-11 08:48:19 -070059 DbusPidZone p(zone, minThermalOutput, failSafePercent, m, bus_mock_mode,
60 objPath, defer);
Patrick Venturea58197c2018-06-11 15:29:45 -070061 // Success.
62}
63
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070064} // namespace
Patrick Venturea58197c2018-06-11 15:29:45 -070065
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070066class PidZoneTest : public ::testing::Test
67{
68 protected:
69 PidZoneTest() :
70 property_index(), properties(), sdbus_mock_passive(), sdbus_mock_host(),
71 sdbus_mock_mode()
72 {
73 EXPECT_CALL(sdbus_mock_host,
74 sd_bus_add_object_manager(
75 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
76 .WillOnce(Return(0));
Patrick Venturea58197c2018-06-11 15:29:45 -070077
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070078 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
79 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
80 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
Patrick Venturea58197c2018-06-11 15:29:45 -070081
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070082 // Compiler weirdly not happy about just instantiating mgr(...);
James Feist1fe08952019-05-07 09:17:16 -070083 SensorManager m(bus_mock_passive, bus_mock_host);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070084 mgr = std::move(m);
Patrick Venturea58197c2018-06-11 15:29:45 -070085
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070086 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface,
87 properties, &property_index);
Patrick Venturea58197c2018-06-11 15:29:45 -070088
Patrick Venture597ebd62020-08-11 08:48:19 -070089 zone = std::make_unique<DbusPidZone>(zoneId, minThermalOutput,
90 failSafePercent, mgr,
91 bus_mock_mode, objPath, defer);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070092 }
Patrick Venturea58197c2018-06-11 15:29:45 -070093
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070094 // unused
James Feist0709e2f2020-07-08 10:59:45 -070095 double property_index;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070096 std::vector<std::string> properties;
Patrick Venturea58197c2018-06-11 15:29:45 -070097
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070098 sdbusplus::SdBusMock sdbus_mock_passive;
99 sdbusplus::SdBusMock sdbus_mock_host;
100 sdbusplus::SdBusMock sdbus_mock_mode;
101 int64_t zoneId = 1;
James Feist3484bed2019-02-25 13:28:18 -0800102 double minThermalOutput = 1000.0;
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800103 double failSafePercent = 0.75;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700104 bool defer = true;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700105 const char* objPath = "/path/";
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700106 SensorManager mgr;
Patrick Venturea58197c2018-06-11 15:29:45 -0700107
Patrick Venture597ebd62020-08-11 08:48:19 -0700108 std::unique_ptr<DbusPidZone> zone;
Patrick Venturea58197c2018-06-11 15:29:45 -0700109};
110
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700111TEST_F(PidZoneTest, GetZoneId_ReturnsExpected)
112{
Patrick Venturea58197c2018-06-11 15:29:45 -0700113 // Verifies the zoneId returned is what we expect.
114
Patrick Venture0bbeaf82018-10-30 18:50:31 -0700115 EXPECT_EQ(zoneId, zone->getZoneID());
Patrick Venturea58197c2018-06-11 15:29:45 -0700116}
117
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700118TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected)
119{
Patrick Venturea58197c2018-06-11 15:29:45 -0700120 // Verifies that the zone starts in manual mode. Verifies that one can set
121 // the mode.
122 EXPECT_FALSE(zone->getManualMode());
123
124 zone->setManualMode(true);
125 EXPECT_TRUE(zone->getManualMode());
126}
127
Josh Lehana4146eb2020-10-01 11:49:09 -0700128TEST_F(PidZoneTest, SetManualMode_RedundantWritesEnabledOnceAfterManualMode)
129{
130 // Tests adding a fan PID controller to the zone, and verifies it's
131 // touched during processing.
132
133 std::unique_ptr<PIDController> tpid =
134 std::make_unique<ControllerMock>("fan1", zone.get());
135 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
136
137 // Access the internal pid configuration to clear it out (unrelated to the
138 // test).
139 ec::pid_info_t* info = tpid->getPIDInfo();
140 std::memset(info, 0x00, sizeof(ec::pid_info_t));
141
142 zone->addFanPID(std::move(tpid));
143
144 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
145 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
146 EXPECT_CALL(*tmock, outputProc(_));
147
148 // while zone is in auto mode redundant writes should be disabled
149 EXPECT_FALSE(zone->getRedundantWrite());
150
151 // but switching from manual to auto enables a single redundant write
152 zone->setManualMode(true);
153 zone->setManualMode(false);
154 EXPECT_TRUE(zone->getRedundantWrite());
155
156 // after one iteration of a pid loop redundant write should be cleared
157 zone->processFans();
158 EXPECT_FALSE(zone->getRedundantWrite());
159}
160
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700161TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected)
162{
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700163 // Tests addSetPoint, clearSetPoints, determineMaxSetPointRequest
Nirav Shahccc8bb62022-02-17 21:06:51 -0800164 // and getMinThermalSetPoint.
Patrick Venturea58197c2018-06-11 15:29:45 -0700165
166 // At least one value must be above the minimum thermal setpoint used in
167 // the constructor otherwise it'll choose that value
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800168 std::vector<double> values = {100, 200, 300, 400, 500, 5000};
Patrick Venturea58197c2018-06-11 15:29:45 -0700169 for (auto v : values)
170 {
Nirav Shahccc8bb62022-02-17 21:06:51 -0800171 zone->addSetPoint(v, "");
Patrick Venturea58197c2018-06-11 15:29:45 -0700172 }
173
174 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700175 zone->determineMaxSetPointRequest();
176 EXPECT_EQ(5000, zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700177
178 // Clear the values, so it'll choose the minimum thermal setpoint.
Patrick Venture9bbf3332019-07-16 10:50:37 -0700179 zone->clearSetPoints();
Patrick Venturea58197c2018-06-11 15:29:45 -0700180
181 // This will go through the RPM set point values and grab the maximum.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700182 zone->determineMaxSetPointRequest();
Nirav Shahccc8bb62022-02-17 21:06:51 -0800183 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700184}
185
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700186TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected)
187{
Patrick Venturea58197c2018-06-11 15:29:45 -0700188 // Tests adding several RPM setpoints, however, they're all lower than the
Patrick Venture7280e272019-02-11 10:45:32 -0800189 // configured minimal thermal setpoint RPM value.
Patrick Venturea58197c2018-06-11 15:29:45 -0700190
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800191 std::vector<double> values = {100, 200, 300, 400, 500};
Patrick Venturea58197c2018-06-11 15:29:45 -0700192 for (auto v : values)
193 {
Nirav Shahccc8bb62022-02-17 21:06:51 -0800194 zone->addSetPoint(v, "");
Patrick Venturea58197c2018-06-11 15:29:45 -0700195 }
196
197 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700198 zone->determineMaxSetPointRequest();
Patrick Venturea58197c2018-06-11 15:29:45 -0700199
200 // Verifies the value returned in the minimal thermal rpm set point.
Nirav Shahccc8bb62022-02-17 21:06:51 -0800201 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700202}
203
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700204TEST_F(PidZoneTest, GetFailSafePercent_ReturnsExpected)
205{
Patrick Venturea58197c2018-06-11 15:29:45 -0700206 // Verify the value used to create the object is stored.
207 EXPECT_EQ(failSafePercent, zone->getFailSafePercent());
208}
209
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700210TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors)
211{
Patrick Venturea58197c2018-06-11 15:29:45 -0700212 // This test will add a couple thermal inputs, and verify that the zone
213 // initializes into failsafe mode, and will read each sensor.
214
215 std::string name1 = "temp1";
216 int64_t timeout = 1;
217
218 std::unique_ptr<Sensor> sensor1 =
219 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700220 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700221
222 std::string name2 = "temp2";
223 std::unique_ptr<Sensor> sensor2 =
224 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700225 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700226
227 std::string type = "unchecked";
228 mgr.addSensor(type, name1, std::move(sensor1));
229 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
230 mgr.addSensor(type, name2, std::move(sensor2));
231 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
232
233 // Now that the sensors exist, add them to the zone.
234 zone->addThermalInput(name1);
235 zone->addThermalInput(name2);
236
237 // Initialize Zone
238 zone->initializeCache();
239
240 // Verify now in failsafe mode.
241 EXPECT_TRUE(zone->getFailSafeMode());
242
243 ReadReturn r1;
244 r1.value = 10.0;
245 r1.updated = std::chrono::high_resolution_clock::now();
246 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
247
248 ReadReturn r2;
249 r2.value = 11.0;
250 r2.updated = std::chrono::high_resolution_clock::now();
251 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
252
253 // Read the sensors, this will put the values into the cache.
254 zone->updateSensors();
255
256 // We should no longer be in failsafe mode.
257 EXPECT_FALSE(zone->getFailSafeMode());
258
259 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
260 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
261}
262
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700263TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached)
264{
Patrick Venturea58197c2018-06-11 15:29:45 -0700265 // This will add a couple fan inputs, and verify the values are cached.
266
267 std::string name1 = "fan1";
268 int64_t timeout = 2;
269
270 std::unique_ptr<Sensor> sensor1 =
271 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700272 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700273
274 std::string name2 = "fan2";
275 std::unique_ptr<Sensor> sensor2 =
276 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700277 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700278
279 std::string type = "unchecked";
280 mgr.addSensor(type, name1, std::move(sensor1));
281 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
282 mgr.addSensor(type, name2, std::move(sensor2));
283 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
284
285 // Now that the sensors exist, add them to the zone.
286 zone->addFanInput(name1);
287 zone->addFanInput(name2);
288
289 // Initialize Zone
290 zone->initializeCache();
291
292 ReadReturn r1;
293 r1.value = 10.0;
294 r1.updated = std::chrono::high_resolution_clock::now();
295 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
296
297 ReadReturn r2;
298 r2.value = 11.0;
299 r2.updated = std::chrono::high_resolution_clock::now();
300 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
301
302 // Method under test will read through each fan sensor for the zone and
303 // cache the values.
304 zone->updateFanTelemetry();
305
306 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
307 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
308}
309
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700310TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode)
311{
Patrick Venturea58197c2018-06-11 15:29:45 -0700312 // On the second updateSensors call, the updated timestamp will be beyond
313 // the timeout limit.
314
315 int64_t timeout = 1;
316
317 std::string name1 = "temp1";
318 std::unique_ptr<Sensor> sensor1 =
319 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700320 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700321
322 std::string name2 = "temp2";
323 std::unique_ptr<Sensor> sensor2 =
324 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700325 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700326
327 std::string type = "unchecked";
328 mgr.addSensor(type, name1, std::move(sensor1));
329 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
330 mgr.addSensor(type, name2, std::move(sensor2));
331 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
332
333 zone->addThermalInput(name1);
334 zone->addThermalInput(name2);
335
336 // Initialize Zone
337 zone->initializeCache();
338
339 // Verify now in failsafe mode.
340 EXPECT_TRUE(zone->getFailSafeMode());
341
342 ReadReturn r1;
343 r1.value = 10.0;
344 r1.updated = std::chrono::high_resolution_clock::now();
345 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
346
347 ReadReturn r2;
348 r2.value = 11.0;
349 r2.updated = std::chrono::high_resolution_clock::now();
350 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
351
352 zone->updateSensors();
353 EXPECT_FALSE(zone->getFailSafeMode());
354
355 // Ok, so we're not in failsafe mode, so let's set updated to the past.
356 // sensor1 will have an updated field older than its timeout value, but
357 // sensor2 will be fine. :D
358 r1.updated -= std::chrono::seconds(3);
359 r2.updated = std::chrono::high_resolution_clock::now();
360
361 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
362 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
363
364 // Method under test will read each sensor. One sensor's value is older
365 // than the timeout for that sensor and this triggers failsafe mode.
366 zone->updateSensors();
367 EXPECT_TRUE(zone->getFailSafeMode());
368}
369
Will Liangded0ab52019-05-15 17:10:06 +0800370TEST_F(PidZoneTest, FanInputTest_FailsafeToValid_ReadsSensors)
371{
372 // This will add a couple fan inputs, and verify the values are cached.
373
374 std::string name1 = "fan1";
375 int64_t timeout = 2;
376
377 std::unique_ptr<Sensor> sensor1 =
378 std::make_unique<SensorMock>(name1, timeout);
379 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
380
381 std::string name2 = "fan2";
382 std::unique_ptr<Sensor> sensor2 =
383 std::make_unique<SensorMock>(name2, timeout);
384 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
385
386 std::string type = "unchecked";
387 mgr.addSensor(type, name1, std::move(sensor1));
388 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
389 mgr.addSensor(type, name2, std::move(sensor2));
390 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
391
392 // Now that the sensors exist, add them to the zone.
393 zone->addFanInput(name1);
394 zone->addFanInput(name2);
395
396 // Initialize Zone
397 zone->initializeCache();
398
399 // Verify now in failsafe mode.
400 EXPECT_TRUE(zone->getFailSafeMode());
401
402 ReadReturn r1;
403 r1.value = 10.0;
404 r1.updated = std::chrono::high_resolution_clock::now();
405 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
406
407 ReadReturn r2;
408 r2.value = 11.0;
409 r2.updated = std::chrono::high_resolution_clock::now();
410 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
411
412 // Method under test will read through each fan sensor for the zone and
413 // cache the values.
414 zone->updateFanTelemetry();
415
416 // We should no longer be in failsafe mode.
417 EXPECT_FALSE(zone->getFailSafeMode());
418
419 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
420 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
421}
422
423TEST_F(PidZoneTest, FanInputTest_ValueTimeoutEntersFailSafeMode)
424{
425 // This will add a couple fan inputs, and verify the values are cached.
426
427 std::string name1 = "fan1";
428 int64_t timeout = 2;
429
430 std::unique_ptr<Sensor> sensor1 =
431 std::make_unique<SensorMock>(name1, timeout);
432 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
433
434 std::string name2 = "fan2";
435 std::unique_ptr<Sensor> sensor2 =
436 std::make_unique<SensorMock>(name2, timeout);
437 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
438
439 std::string type = "unchecked";
440 mgr.addSensor(type, name1, std::move(sensor1));
441 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
442 mgr.addSensor(type, name2, std::move(sensor2));
443 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
444
445 // Now that the sensors exist, add them to the zone.
446 zone->addFanInput(name1);
447 zone->addFanInput(name2);
448
449 // Initialize Zone
450 zone->initializeCache();
451
452 // Verify now in failsafe mode.
453 EXPECT_TRUE(zone->getFailSafeMode());
454
455 ReadReturn r1;
456 r1.value = 10.0;
457 r1.updated = std::chrono::high_resolution_clock::now();
458 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
459
460 ReadReturn r2;
461 r2.value = 11.0;
462 r2.updated = std::chrono::high_resolution_clock::now();
463 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
464
465 // Method under test will read through each fan sensor for the zone and
466 // cache the values.
467 zone->updateFanTelemetry();
468
469 // We should no longer be in failsafe mode.
470 EXPECT_FALSE(zone->getFailSafeMode());
471
472 r1.updated -= std::chrono::seconds(3);
473 r2.updated = std::chrono::high_resolution_clock::now();
474
475 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
476 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
477
478 zone->updateFanTelemetry();
479 EXPECT_TRUE(zone->getFailSafeMode());
480}
481
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700482TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected)
483{
Patrick Venturea58197c2018-06-11 15:29:45 -0700484 // One can grab a sensor from the manager through the zone.
485
486 int64_t timeout = 1;
487
488 std::string name1 = "temp1";
489 std::unique_ptr<Sensor> sensor1 =
490 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700491 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700492
493 std::string type = "unchecked";
494 mgr.addSensor(type, name1, std::move(sensor1));
495 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
496
497 zone->addThermalInput(name1);
498
499 // Verify method under test returns the pointer we expect.
500 EXPECT_EQ(mgr.getSensor(name1), zone->getSensor(name1));
501}
502
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700503TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed)
504{
Patrick Venturea58197c2018-06-11 15:29:45 -0700505 // Tests adding a thermal PID controller to the zone, and verifies it's
506 // touched during processing.
507
508 std::unique_ptr<PIDController> tpid =
509 std::make_unique<ControllerMock>("thermal1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700510 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700511
512 // Access the internal pid configuration to clear it out (unrelated to the
513 // test).
Patrick Venture563a3562018-10-30 09:31:26 -0700514 ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700515 std::memset(info, 0x00, sizeof(ec::pid_info_t));
516
517 zone->addThermalPID(std::move(tpid));
518
Patrick Venture563a3562018-10-30 09:31:26 -0700519 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
520 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
521 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700522
523 // Method under test will, for each thermal PID, call setpt, input, and
524 // output.
Patrick Venture563a3562018-10-30 09:31:26 -0700525 zone->processThermals();
Patrick Venturea58197c2018-06-11 15:29:45 -0700526}
527
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700528TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed)
529{
Patrick Venturea58197c2018-06-11 15:29:45 -0700530 // Tests adding a fan PID controller to the zone, and verifies it's
531 // touched during processing.
532
533 std::unique_ptr<PIDController> tpid =
534 std::make_unique<ControllerMock>("fan1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700535 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700536
537 // Access the internal pid configuration to clear it out (unrelated to the
538 // test).
Patrick Venture563a3562018-10-30 09:31:26 -0700539 ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700540 std::memset(info, 0x00, sizeof(ec::pid_info_t));
541
542 zone->addFanPID(std::move(tpid));
543
Patrick Venture563a3562018-10-30 09:31:26 -0700544 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
545 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
546 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700547
548 // Method under test will, for each fan PID, call setpt, input, and output.
Patrick Venture563a3562018-10-30 09:31:26 -0700549 zone->processFans();
Patrick Venturea58197c2018-06-11 15:29:45 -0700550}
551
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700552TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected)
553{
Patrick Venturea58197c2018-06-11 15:29:45 -0700554 // The manual(bool) method is inherited from the dbus mode interface.
555
556 // Verifies that someone doesn't remove the internal call to the dbus
557 // object from which we're inheriting.
558 EXPECT_CALL(sdbus_mock_mode,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700559 sd_bus_emit_properties_changed_strv(
560 IsNull(), StrEq(objPath), StrEq(modeInterface), NotNull()))
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700561 .WillOnce(Invoke([&](sd_bus* bus, const char* path,
Hao Jiang841931d2021-02-24 14:45:40 -0800562 const char* interface, const char** names) {
Patrick Venturea58197c2018-06-11 15:29:45 -0700563 EXPECT_STREQ("Manual", names[0]);
564 return 0;
565 }));
566
567 // Method under test will set the manual mode to true and broadcast this
568 // change on dbus.
569 zone->manual(true);
570 EXPECT_TRUE(zone->getManualMode());
571}
572
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700573TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected)
574{
Patrick Venturea58197c2018-06-11 15:29:45 -0700575 // This property is implemented by us as read-only, such that trying to
576 // write to it will have no effect.
577 EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode());
578}
Patrick Venturea0764872020-08-08 07:48:43 -0700579
580} // namespace
581} // namespace pid_control