blob: 47b3f9784561a31bf866a21871c5193a33da82f8 [file] [log] [blame]
James Zheng6df8bb52024-11-27 23:38:47 +00001#include "failsafeloggers/builder.hpp"
2#include "failsafeloggers/failsafe_logger.hpp"
3#include "failsafeloggers/failsafe_logger_utility.hpp"
Josh Lehande745422020-11-07 02:14:09 -08004#include "pid/ec/logging.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07005#include "pid/ec/pid.hpp"
Patrick Venturea58197c2018-06-11 15:29:45 -07006#include "pid/zone.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07007#include "sensors/manager.hpp"
8#include "test/controller_mock.hpp"
9#include "test/helpers.hpp"
10#include "test/sensor_mock.hpp"
Patrick Venturea58197c2018-06-11 15:29:45 -070011
Patrick Venturea83a3ec2020-08-04 09:52:05 -070012#include <sdbusplus/test/sdbus_mock.hpp>
13
Patrick Venturea58197c2018-06-11 15:29:45 -070014#include <chrono>
15#include <cstring>
James Zheng6df8bb52024-11-27 23:38:47 +000016#include <unordered_map>
Patrick Venturea58197c2018-06-11 15:29:45 -070017#include <vector>
18
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070019#include <gmock/gmock.h>
20#include <gtest/gtest.h>
Patrick Venturea58197c2018-06-11 15:29:45 -070021
Patrick Venturea0764872020-08-08 07:48:43 -070022namespace pid_control
23{
24namespace
25{
26
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070027using ::testing::_;
Patrick Venturea58197c2018-06-11 15:29:45 -070028using ::testing::IsNull;
29using ::testing::Return;
30using ::testing::StrEq;
Patrick Venturea58197c2018-06-11 15:29:45 -070031
32static std::string modeInterface = "xyz.openbmc_project.Control.Mode";
Harvey Wucc0232a2023-02-09 14:58:55 +080033static std::string debugZoneInterface = "xyz.openbmc_project.Debug.Pid.Zone";
ykchiu7c6d35d2023-05-10 17:01:46 +080034static std::string enableInterface = "xyz.openbmc_project.Object.Enable";
Harvey Wu37180062023-10-02 09:42:50 +080035static std::string debugThermalPowerInterface =
36 "xyz.openbmc_project.Debug.Pid.ThermalPower";
Patrick Venturea58197c2018-06-11 15:29:45 -070037
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070038namespace
39{
Patrick Venturea58197c2018-06-11 15:29:45 -070040
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070041TEST(PidZoneConstructorTest, BoringConstructorTest)
42{
Patrick Venturea58197c2018-06-11 15:29:45 -070043 // Build a PID Zone.
44
ykchiu7c6d35d2023-05-10 17:01:46 +080045 sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode,
46 sdbus_mock_enable;
Patrick Venturea58197c2018-06-11 15:29:45 -070047 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
48 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
49 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
ykchiu7c6d35d2023-05-10 17:01:46 +080050 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
Patrick Venturea58197c2018-06-11 15:29:45 -070051
52 EXPECT_CALL(sdbus_mock_host,
53 sd_bus_add_object_manager(
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070054 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
Patrick Venturea58197c2018-06-11 15:29:45 -070055 .WillOnce(Return(0));
56
James Feist1fe08952019-05-07 09:17:16 -070057 SensorManager m(bus_mock_passive, bus_mock_host);
Patrick Venturea58197c2018-06-11 15:29:45 -070058
59 bool defer = true;
Delphine CC Chiu97889632023-11-06 11:32:46 +080060 bool accSetPoint = false;
Patrick Venturee2ec0f62018-09-04 12:30:27 -070061 const char* objPath = "/path/";
Patrick Venturea58197c2018-06-11 15:29:45 -070062 int64_t zone = 1;
James Feist3484bed2019-02-25 13:28:18 -080063 double minThermalOutput = 1000.0;
Harvey Wu92f9f3c2023-11-07 09:23:35 +080064 double failSafePercent = 100;
Bonnie Lo0e8fc392022-10-05 10:20:55 +080065 conf::CycleTime cycleTime;
Patrick Venturea58197c2018-06-11 15:29:45 -070066
James Feist0709e2f2020-07-08 10:59:45 -070067 double d;
Patrick Venturea58197c2018-06-11 15:29:45 -070068 std::vector<std::string> properties;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070069 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, properties,
James Feist0709e2f2020-07-08 10:59:45 -070070 &d);
Harvey Wucc0232a2023-02-09 14:58:55 +080071 SetupDbusObject(&sdbus_mock_mode, defer, objPath, debugZoneInterface,
72 properties, &d);
Patrick Venturea58197c2018-06-11 15:29:45 -070073
ykchiu7c6d35d2023-05-10 17:01:46 +080074 std::string sensorname = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -040075 std::string pidsensorpath =
76 "/xyz/openbmc_project/settings/fanctrl/zone1/" + sensorname;
ykchiu7c6d35d2023-05-10 17:01:46 +080077
78 double de;
79 std::vector<std::string> propertiesenable;
80 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
81 enableInterface, propertiesenable, &de);
82
Bonnie Lo0e8fc392022-10-05 10:20:55 +080083 DbusPidZone p(zone, minThermalOutput, failSafePercent, cycleTime, m,
Delphine CC Chiu97889632023-11-06 11:32:46 +080084 bus_mock_mode, objPath, defer, accSetPoint);
Patrick Venturea58197c2018-06-11 15:29:45 -070085 // Success.
86}
87
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070088} // namespace
Patrick Venturea58197c2018-06-11 15:29:45 -070089
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070090class PidZoneTest : public ::testing::Test
91{
92 protected:
93 PidZoneTest() :
94 property_index(), properties(), sdbus_mock_passive(), sdbus_mock_host(),
ykchiu7c6d35d2023-05-10 17:01:46 +080095 sdbus_mock_mode(), sdbus_mock_enable()
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070096 {
97 EXPECT_CALL(sdbus_mock_host,
98 sd_bus_add_object_manager(
99 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
100 .WillOnce(Return(0));
Patrick Venturea58197c2018-06-11 15:29:45 -0700101
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700102 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
103 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
104 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
ykchiu7c6d35d2023-05-10 17:01:46 +0800105 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
Patrick Venturea58197c2018-06-11 15:29:45 -0700106
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700107 // Compiler weirdly not happy about just instantiating mgr(...);
James Feist1fe08952019-05-07 09:17:16 -0700108 SensorManager m(bus_mock_passive, bus_mock_host);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700109 mgr = std::move(m);
Patrick Venturea58197c2018-06-11 15:29:45 -0700110
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700111 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface,
112 properties, &property_index);
Harvey Wucc0232a2023-02-09 14:58:55 +0800113 SetupDbusObject(&sdbus_mock_mode, defer, objPath, debugZoneInterface,
114 properties, &property_index);
Patrick Venturea58197c2018-06-11 15:29:45 -0700115
ykchiu7c6d35d2023-05-10 17:01:46 +0800116 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
117 enableInterface, propertiesenable,
118 &propertyenable_index);
119
Delphine CC Chiu97889632023-11-06 11:32:46 +0800120 zone = std::make_unique<DbusPidZone>(
121 zoneId, minThermalOutput, failSafePercent, cycleTime, mgr,
122 bus_mock_mode, objPath, defer, accSetPoint);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700123 }
Patrick Venturea58197c2018-06-11 15:29:45 -0700124
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700125 // unused
James Feist0709e2f2020-07-08 10:59:45 -0700126 double property_index;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700127 std::vector<std::string> properties;
ykchiu7c6d35d2023-05-10 17:01:46 +0800128 double propertyenable_index;
129 std::vector<std::string> propertiesenable;
Patrick Venturea58197c2018-06-11 15:29:45 -0700130
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700131 sdbusplus::SdBusMock sdbus_mock_passive;
132 sdbusplus::SdBusMock sdbus_mock_host;
133 sdbusplus::SdBusMock sdbus_mock_mode;
ykchiu7c6d35d2023-05-10 17:01:46 +0800134 sdbusplus::SdBusMock sdbus_mock_enable;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700135 int64_t zoneId = 1;
James Feist3484bed2019-02-25 13:28:18 -0800136 double minThermalOutput = 1000.0;
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800137 double failSafePercent = 100;
Harvey Wu37180062023-10-02 09:42:50 +0800138 double setpoint = 50.0;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700139 bool defer = true;
Delphine CC Chiu97889632023-11-06 11:32:46 +0800140 bool accSetPoint = false;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700141 const char* objPath = "/path/";
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700142 SensorManager mgr;
Bonnie Lo0e8fc392022-10-05 10:20:55 +0800143 conf::CycleTime cycleTime;
Patrick Venturea58197c2018-06-11 15:29:45 -0700144
ykchiu7c6d35d2023-05-10 17:01:46 +0800145 std::string sensorname = "temp1";
Harvey Wu37180062023-10-02 09:42:50 +0800146 std::string sensorType = "temp";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400147 std::string pidsensorpath =
148 "/xyz/openbmc_project/settings/fanctrl/zone1/" + sensorname;
ykchiu7c6d35d2023-05-10 17:01:46 +0800149
Patrick Venture597ebd62020-08-11 08:48:19 -0700150 std::unique_ptr<DbusPidZone> zone;
Patrick Venturea58197c2018-06-11 15:29:45 -0700151};
152
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700153TEST_F(PidZoneTest, GetZoneId_ReturnsExpected)
154{
Patrick Venturea58197c2018-06-11 15:29:45 -0700155 // Verifies the zoneId returned is what we expect.
156
Patrick Venture0bbeaf82018-10-30 18:50:31 -0700157 EXPECT_EQ(zoneId, zone->getZoneID());
Patrick Venturea58197c2018-06-11 15:29:45 -0700158}
159
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700160TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected)
161{
Patrick Venturea58197c2018-06-11 15:29:45 -0700162 // Verifies that the zone starts in manual mode. Verifies that one can set
163 // the mode.
164 EXPECT_FALSE(zone->getManualMode());
165
166 zone->setManualMode(true);
167 EXPECT_TRUE(zone->getManualMode());
168}
169
ykchiu7c6d35d2023-05-10 17:01:46 +0800170TEST_F(PidZoneTest, AddPidControlProcessGetAndSetEnableTest_BehavesAsExpected)
171{
172 // Verifies that the zone starts in enable mode. Verifies that one can set
173 // enable the mode.
174 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
175
176 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
177 IsNull(), StrEq(pidsensorpath.c_str()),
178 StrEq(enableInterface), NotNull()))
179 .Times(::testing::AnyNumber())
180 .WillOnce(Invoke(
181 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
182 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400183 EXPECT_STREQ("Enable", names[0]);
184 return 0;
185 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800186
Harvey Wu37180062023-10-02 09:42:50 +0800187 zone->addPidControlProcess(sensorname, sensorType, setpoint,
188 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800189 EXPECT_TRUE(zone->isPidProcessEnabled(sensorname));
190}
191
Josh Lehana4146eb2020-10-01 11:49:09 -0700192TEST_F(PidZoneTest, SetManualMode_RedundantWritesEnabledOnceAfterManualMode)
193{
194 // Tests adding a fan PID controller to the zone, and verifies it's
195 // touched during processing.
196
197 std::unique_ptr<PIDController> tpid =
198 std::make_unique<ControllerMock>("fan1", zone.get());
199 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
200
201 // Access the internal pid configuration to clear it out (unrelated to the
202 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800203 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Josh Lehana4146eb2020-10-01 11:49:09 -0700204
205 zone->addFanPID(std::move(tpid));
206
207 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
208 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
209 EXPECT_CALL(*tmock, outputProc(_));
210
211 // while zone is in auto mode redundant writes should be disabled
212 EXPECT_FALSE(zone->getRedundantWrite());
213
214 // but switching from manual to auto enables a single redundant write
215 zone->setManualMode(true);
216 zone->setManualMode(false);
217 EXPECT_TRUE(zone->getRedundantWrite());
218
219 // after one iteration of a pid loop redundant write should be cleared
220 zone->processFans();
221 EXPECT_FALSE(zone->getRedundantWrite());
222}
223
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700224TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected)
225{
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700226 // Tests addSetPoint, clearSetPoints, determineMaxSetPointRequest
Nirav Shahccc8bb62022-02-17 21:06:51 -0800227 // and getMinThermalSetPoint.
Patrick Venturea58197c2018-06-11 15:29:45 -0700228
ykchiu7c6d35d2023-05-10 17:01:46 +0800229 // Need to add pid control process for the zone that can enable
230 // the process and add the set point.
231 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
232
233 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
234 IsNull(), StrEq(pidsensorpath.c_str()),
235 StrEq(enableInterface), NotNull()))
236 .Times(::testing::AnyNumber())
237 .WillOnce(Invoke(
238 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
239 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400240 EXPECT_STREQ("Enable", names[0]);
241 return 0;
242 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800243
Harvey Wu37180062023-10-02 09:42:50 +0800244 zone->addPidControlProcess(sensorname, sensorType, setpoint,
245 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800246
Patrick Venturea58197c2018-06-11 15:29:45 -0700247 // At least one value must be above the minimum thermal setpoint used in
248 // the constructor otherwise it'll choose that value
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800249 std::vector<double> values = {100, 200, 300, 400, 500, 5000};
ykchiu7c6d35d2023-05-10 17:01:46 +0800250
Patrick Venturea58197c2018-06-11 15:29:45 -0700251 for (auto v : values)
252 {
ykchiu7c6d35d2023-05-10 17:01:46 +0800253 zone->addSetPoint(v, sensorname);
Patrick Venturea58197c2018-06-11 15:29:45 -0700254 }
255
256 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700257 zone->determineMaxSetPointRequest();
258 EXPECT_EQ(5000, zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700259
260 // Clear the values, so it'll choose the minimum thermal setpoint.
Patrick Venture9bbf3332019-07-16 10:50:37 -0700261 zone->clearSetPoints();
Patrick Venturea58197c2018-06-11 15:29:45 -0700262
263 // This will go through the RPM set point values and grab the maximum.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700264 zone->determineMaxSetPointRequest();
Nirav Shahccc8bb62022-02-17 21:06:51 -0800265 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700266}
267
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700268TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected)
269{
Patrick Venturea58197c2018-06-11 15:29:45 -0700270 // Tests adding several RPM setpoints, however, they're all lower than the
Patrick Venture7280e272019-02-11 10:45:32 -0800271 // configured minimal thermal setpoint RPM value.
Patrick Venturea58197c2018-06-11 15:29:45 -0700272
ykchiu7c6d35d2023-05-10 17:01:46 +0800273 // Need to add pid control process for the zone that can enable
274 // the process and add the set point.
275 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
276
277 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
278 IsNull(), StrEq(pidsensorpath.c_str()),
279 StrEq(enableInterface), NotNull()))
280 .Times(::testing::AnyNumber())
281 .WillOnce(Invoke(
282 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
283 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400284 EXPECT_STREQ("Enable", names[0]);
285 return 0;
286 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800287
Harvey Wu37180062023-10-02 09:42:50 +0800288 zone->addPidControlProcess(sensorname, sensorType, setpoint,
289 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800290
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800291 std::vector<double> values = {100, 200, 300, 400, 500};
ykchiu7c6d35d2023-05-10 17:01:46 +0800292
Patrick Venturea58197c2018-06-11 15:29:45 -0700293 for (auto v : values)
294 {
ykchiu7c6d35d2023-05-10 17:01:46 +0800295 zone->addSetPoint(v, sensorname);
Patrick Venturea58197c2018-06-11 15:29:45 -0700296 }
297
298 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700299 zone->determineMaxSetPointRequest();
Patrick Venturea58197c2018-06-11 15:29:45 -0700300
301 // Verifies the value returned in the minimal thermal rpm set point.
Nirav Shahccc8bb62022-02-17 21:06:51 -0800302 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700303}
304
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800305TEST_F(PidZoneTest, GetFailSafePercent_SingleFailedReturnsExpected)
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700306{
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800307 // Tests when only one sensor failed and the sensor's failsafe duty is zero,
308 // and verify that the sensor name is empty and failsafe duty is PID zone's
309 // failsafe duty.
ykchiu9fe3a3c2023-05-11 13:43:54 +0800310
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800311 std::vector<std::string> input1 = {"temp1"};
312 std::vector<std::string> input2 = {"temp2"};
313 std::vector<std::string> input3 = {"temp3"};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800314 std::vector<double> values = {0, 0, 0};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800315
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800316 zone->addPidFailSafePercent(input1, values[0]);
317 zone->addPidFailSafePercent(input2, values[1]);
318 zone->addPidFailSafePercent(input3, values[2]);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800319
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800320 zone->markSensorMissing("temp1");
ykchiu9fe3a3c2023-05-11 13:43:54 +0800321
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800322 EXPECT_EQ(failSafePercent, zone->getFailSafePercent());
ykchiu9fe3a3c2023-05-11 13:43:54 +0800323}
324
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800325TEST_F(PidZoneTest, GetFailSafePercent_MultiFailedReturnsExpected)
ykchiu9fe3a3c2023-05-11 13:43:54 +0800326{
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800327 // Tests when multi sensor failed, and verify the final failsafe's sensor
328 // name and duty as expected.
ykchiu9fe3a3c2023-05-11 13:43:54 +0800329
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800330 std::vector<std::string> input1 = {"temp1"};
331 std::vector<std::string> input2 = {"temp2"};
332 std::vector<std::string> input3 = {"temp3"};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800333 std::vector<double> values = {60, 80, 70};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800334
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800335 zone->addPidFailSafePercent(input1, values[0]);
336 zone->addPidFailSafePercent(input2, values[1]);
337 zone->addPidFailSafePercent(input3, values[2]);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800338
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800339 zone->markSensorMissing("temp1");
340 zone->markSensorMissing("temp2");
341 zone->markSensorMissing("temp3");
ykchiu9fe3a3c2023-05-11 13:43:54 +0800342
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800343 EXPECT_EQ(80, zone->getFailSafePercent());
Patrick Venturea58197c2018-06-11 15:29:45 -0700344}
345
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700346TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors)
347{
Patrick Venturea58197c2018-06-11 15:29:45 -0700348 // This test will add a couple thermal inputs, and verify that the zone
349 // initializes into failsafe mode, and will read each sensor.
350
James Zheng6df8bb52024-11-27 23:38:47 +0000351 // Disable failsafe logger for the unit test.
352 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
353 buildFailsafeLoggers(empty_zone_map, 0);
354
Patrick Venturea58197c2018-06-11 15:29:45 -0700355 std::string name1 = "temp1";
356 int64_t timeout = 1;
357
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400358 std::unique_ptr<Sensor> sensor1 =
359 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700360 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700361
362 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400363 std::unique_ptr<Sensor> sensor2 =
364 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700365 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700366
367 std::string type = "unchecked";
368 mgr.addSensor(type, name1, std::move(sensor1));
369 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
370 mgr.addSensor(type, name2, std::move(sensor2));
371 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
372
373 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800374 zone->addThermalInput(name1, false);
375 zone->addThermalInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700376
377 // Initialize Zone
378 zone->initializeCache();
379
380 // Verify now in failsafe mode.
381 EXPECT_TRUE(zone->getFailSafeMode());
382
383 ReadReturn r1;
384 r1.value = 10.0;
385 r1.updated = std::chrono::high_resolution_clock::now();
386 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
387
388 ReadReturn r2;
389 r2.value = 11.0;
390 r2.updated = std::chrono::high_resolution_clock::now();
391 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
392
393 // Read the sensors, this will put the values into the cache.
394 zone->updateSensors();
395
396 // We should no longer be in failsafe mode.
397 EXPECT_FALSE(zone->getFailSafeMode());
398
399 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
400 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
401}
402
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700403TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached)
404{
Patrick Venturea58197c2018-06-11 15:29:45 -0700405 // This will add a couple fan inputs, and verify the values are cached.
406
James Zheng6df8bb52024-11-27 23:38:47 +0000407 // Disable failsafe logger for the unit test.
408 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
409 buildFailsafeLoggers(empty_zone_map, 0);
410
Patrick Venturea58197c2018-06-11 15:29:45 -0700411 std::string name1 = "fan1";
412 int64_t timeout = 2;
413
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400414 std::unique_ptr<Sensor> sensor1 =
415 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700416 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700417
418 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400419 std::unique_ptr<Sensor> sensor2 =
420 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700421 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700422
423 std::string type = "unchecked";
424 mgr.addSensor(type, name1, std::move(sensor1));
425 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
426 mgr.addSensor(type, name2, std::move(sensor2));
427 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
428
429 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800430 zone->addFanInput(name1, false);
431 zone->addFanInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700432
433 // Initialize Zone
434 zone->initializeCache();
435
436 ReadReturn r1;
437 r1.value = 10.0;
438 r1.updated = std::chrono::high_resolution_clock::now();
439 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
440
441 ReadReturn r2;
442 r2.value = 11.0;
443 r2.updated = std::chrono::high_resolution_clock::now();
444 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
445
446 // Method under test will read through each fan sensor for the zone and
447 // cache the values.
448 zone->updateFanTelemetry();
449
450 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
451 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
452}
453
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700454TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode)
455{
Patrick Venturea58197c2018-06-11 15:29:45 -0700456 // On the second updateSensors call, the updated timestamp will be beyond
457 // the timeout limit.
458
James Zheng6df8bb52024-11-27 23:38:47 +0000459 // Disable failsafe logger for the unit test.
460 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
461 buildFailsafeLoggers(empty_zone_map, 0);
462
Patrick Venturea58197c2018-06-11 15:29:45 -0700463 int64_t timeout = 1;
464
465 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400466 std::unique_ptr<Sensor> sensor1 =
467 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700468 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700469
470 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400471 std::unique_ptr<Sensor> sensor2 =
472 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700473 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700474
475 std::string type = "unchecked";
476 mgr.addSensor(type, name1, std::move(sensor1));
477 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
478 mgr.addSensor(type, name2, std::move(sensor2));
479 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
480
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800481 zone->addThermalInput(name1, false);
482 zone->addThermalInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700483
484 // Initialize Zone
485 zone->initializeCache();
486
487 // Verify now in failsafe mode.
488 EXPECT_TRUE(zone->getFailSafeMode());
489
490 ReadReturn r1;
491 r1.value = 10.0;
492 r1.updated = std::chrono::high_resolution_clock::now();
493 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
494
495 ReadReturn r2;
496 r2.value = 11.0;
497 r2.updated = std::chrono::high_resolution_clock::now();
498 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
499
500 zone->updateSensors();
501 EXPECT_FALSE(zone->getFailSafeMode());
502
503 // Ok, so we're not in failsafe mode, so let's set updated to the past.
504 // sensor1 will have an updated field older than its timeout value, but
505 // sensor2 will be fine. :D
506 r1.updated -= std::chrono::seconds(3);
507 r2.updated = std::chrono::high_resolution_clock::now();
508
509 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
510 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
511
512 // Method under test will read each sensor. One sensor's value is older
513 // than the timeout for that sensor and this triggers failsafe mode.
514 zone->updateSensors();
515 EXPECT_TRUE(zone->getFailSafeMode());
516}
517
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800518TEST_F(PidZoneTest, ThermalInput_MissingIsAcceptableNoFailSafe)
519{
520 // This is similar to the above test, but because missingIsAcceptable
521 // is set for sensor1, the zone should not enter failsafe mode when
522 // only sensor1 goes missing.
523 // However, sensor2 going missing should still trigger failsafe mode.
524
James Zheng6df8bb52024-11-27 23:38:47 +0000525 // Disable failsafe logger for the unit test.
526 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
527 buildFailsafeLoggers(empty_zone_map, 0);
528
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800529 int64_t timeout = 1;
530
531 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400532 std::unique_ptr<Sensor> sensor1 =
533 std::make_unique<SensorMock>(name1, timeout);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800534 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
535
536 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400537 std::unique_ptr<Sensor> sensor2 =
538 std::make_unique<SensorMock>(name2, timeout);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800539 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
540
541 std::string type = "unchecked";
542 mgr.addSensor(type, name1, std::move(sensor1));
543 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
544 mgr.addSensor(type, name2, std::move(sensor2));
545 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
546
547 // Only sensor1 has MissingIsAcceptable enabled for it
548 zone->addThermalInput(name1, true);
549 zone->addThermalInput(name2, false);
550
551 // Initialize Zone
552 zone->initializeCache();
553
554 // As sensors are not initialized, zone should be in failsafe mode
555 EXPECT_TRUE(zone->getFailSafeMode());
556
557 // r1 not populated here, intentionally, to simulate a sensor that
558 // is not available yet, perhaps takes a long time to start up.
559 ReadReturn r1;
560 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
561
562 ReadReturn r2;
563 r2.value = 11.0;
564 r2.updated = std::chrono::high_resolution_clock::now();
565 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
566
567 zone->updateSensors();
568
569 // Only sensor2 has been initialized here. Failsafe should be false,
570 // because sensor1 MissingIsAcceptable so it is OK for it to go missing.
571 EXPECT_FALSE(zone->getFailSafeMode());
572
573 r1.value = 10.0;
574 r1.updated = std::chrono::high_resolution_clock::now();
575
576 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
577 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
578 zone->updateSensors();
579
580 // Both sensors are now properly initialized
581 EXPECT_FALSE(zone->getFailSafeMode());
582
583 // Ok, so we're not in failsafe mode, so let's set updated to the past.
584 // sensor1 will have an updated field older than its timeout value, but
585 // sensor2 will be fine. :D
586 r1.updated -= std::chrono::seconds(3);
587 r2.updated = std::chrono::high_resolution_clock::now();
588
589 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
590 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
591 zone->updateSensors();
592
593 // MissingIsAcceptable is true for sensor1, so the zone should not be
594 // thrown into failsafe mode.
595 EXPECT_FALSE(zone->getFailSafeMode());
596
597 // Do the same thing, but for the opposite sensors: r1 is good,
598 // but r2 is set to some time in the past.
599 r1.updated = std::chrono::high_resolution_clock::now();
600 r2.updated -= std::chrono::seconds(3);
601
602 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
603 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
604 zone->updateSensors();
605
606 // Now, the zone should be in failsafe mode, because sensor2 does not
607 // have MissingIsAcceptable set true, it is still subject to failsafe.
608 EXPECT_TRUE(zone->getFailSafeMode());
609
610 r1.updated = std::chrono::high_resolution_clock::now();
611 r2.updated = std::chrono::high_resolution_clock::now();
612
613 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
614 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
615 zone->updateSensors();
616
617 // The failsafe mode should cease, as both sensors are good again.
618 EXPECT_FALSE(zone->getFailSafeMode());
619}
620
Will Liangded0ab52019-05-15 17:10:06 +0800621TEST_F(PidZoneTest, FanInputTest_FailsafeToValid_ReadsSensors)
622{
623 // This will add a couple fan inputs, and verify the values are cached.
624
James Zheng6df8bb52024-11-27 23:38:47 +0000625 // Disable failsafe logger for the unit test.
626 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
627 buildFailsafeLoggers(empty_zone_map, 0);
628
Will Liangded0ab52019-05-15 17:10:06 +0800629 std::string name1 = "fan1";
630 int64_t timeout = 2;
631
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400632 std::unique_ptr<Sensor> sensor1 =
633 std::make_unique<SensorMock>(name1, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800634 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
635
636 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400637 std::unique_ptr<Sensor> sensor2 =
638 std::make_unique<SensorMock>(name2, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800639 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
640
641 std::string type = "unchecked";
642 mgr.addSensor(type, name1, std::move(sensor1));
643 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
644 mgr.addSensor(type, name2, std::move(sensor2));
645 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
646
647 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800648 zone->addFanInput(name1, false);
649 zone->addFanInput(name2, false);
Will Liangded0ab52019-05-15 17:10:06 +0800650
651 // Initialize Zone
652 zone->initializeCache();
653
654 // Verify now in failsafe mode.
655 EXPECT_TRUE(zone->getFailSafeMode());
656
657 ReadReturn r1;
658 r1.value = 10.0;
659 r1.updated = std::chrono::high_resolution_clock::now();
660 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
661
662 ReadReturn r2;
663 r2.value = 11.0;
664 r2.updated = std::chrono::high_resolution_clock::now();
665 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
666
667 // Method under test will read through each fan sensor for the zone and
668 // cache the values.
669 zone->updateFanTelemetry();
670
671 // We should no longer be in failsafe mode.
672 EXPECT_FALSE(zone->getFailSafeMode());
673
674 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
675 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
676}
677
678TEST_F(PidZoneTest, FanInputTest_ValueTimeoutEntersFailSafeMode)
679{
680 // This will add a couple fan inputs, and verify the values are cached.
681
James Zheng6df8bb52024-11-27 23:38:47 +0000682 // Disable failsafe logger for the unit test.
683 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
684 buildFailsafeLoggers(empty_zone_map, 0);
685
Will Liangded0ab52019-05-15 17:10:06 +0800686 std::string name1 = "fan1";
687 int64_t timeout = 2;
688
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400689 std::unique_ptr<Sensor> sensor1 =
690 std::make_unique<SensorMock>(name1, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800691 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
692
693 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400694 std::unique_ptr<Sensor> sensor2 =
695 std::make_unique<SensorMock>(name2, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800696 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
697
698 std::string type = "unchecked";
699 mgr.addSensor(type, name1, std::move(sensor1));
700 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
701 mgr.addSensor(type, name2, std::move(sensor2));
702 EXPECT_EQ(mgr.getSensor(name2), sensor_ptr2);
703
704 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800705 zone->addFanInput(name1, false);
706 zone->addFanInput(name2, false);
Will Liangded0ab52019-05-15 17:10:06 +0800707
708 // Initialize Zone
709 zone->initializeCache();
710
711 // Verify now in failsafe mode.
712 EXPECT_TRUE(zone->getFailSafeMode());
713
714 ReadReturn r1;
715 r1.value = 10.0;
716 r1.updated = std::chrono::high_resolution_clock::now();
717 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
718
719 ReadReturn r2;
720 r2.value = 11.0;
721 r2.updated = std::chrono::high_resolution_clock::now();
722 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
723
724 // Method under test will read through each fan sensor for the zone and
725 // cache the values.
726 zone->updateFanTelemetry();
727
728 // We should no longer be in failsafe mode.
729 EXPECT_FALSE(zone->getFailSafeMode());
730
731 r1.updated -= std::chrono::seconds(3);
732 r2.updated = std::chrono::high_resolution_clock::now();
733
734 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
735 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
736
737 zone->updateFanTelemetry();
738 EXPECT_TRUE(zone->getFailSafeMode());
739}
740
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700741TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected)
742{
Patrick Venturea58197c2018-06-11 15:29:45 -0700743 // One can grab a sensor from the manager through the zone.
744
James Zheng6df8bb52024-11-27 23:38:47 +0000745 // Disable failsafe logger for the unit test.
746 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
747 buildFailsafeLoggers(empty_zone_map, 0);
748
Patrick Venturea58197c2018-06-11 15:29:45 -0700749 int64_t timeout = 1;
750
751 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400752 std::unique_ptr<Sensor> sensor1 =
753 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700754 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700755
756 std::string type = "unchecked";
757 mgr.addSensor(type, name1, std::move(sensor1));
758 EXPECT_EQ(mgr.getSensor(name1), sensor_ptr1);
759
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800760 zone->addThermalInput(name1, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700761
762 // Verify method under test returns the pointer we expect.
763 EXPECT_EQ(mgr.getSensor(name1), zone->getSensor(name1));
764}
765
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700766TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed)
767{
Patrick Venturea58197c2018-06-11 15:29:45 -0700768 // Tests adding a thermal PID controller to the zone, and verifies it's
769 // touched during processing.
770
771 std::unique_ptr<PIDController> tpid =
772 std::make_unique<ControllerMock>("thermal1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700773 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700774
775 // Access the internal pid configuration to clear it out (unrelated to the
776 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800777 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700778
779 zone->addThermalPID(std::move(tpid));
780
Patrick Venture563a3562018-10-30 09:31:26 -0700781 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
782 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
783 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700784
785 // Method under test will, for each thermal PID, call setpt, input, and
786 // output.
Patrick Venture563a3562018-10-30 09:31:26 -0700787 zone->processThermals();
Patrick Venturea58197c2018-06-11 15:29:45 -0700788}
789
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700790TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed)
791{
Patrick Venturea58197c2018-06-11 15:29:45 -0700792 // Tests adding a fan PID controller to the zone, and verifies it's
793 // touched during processing.
794
795 std::unique_ptr<PIDController> tpid =
796 std::make_unique<ControllerMock>("fan1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700797 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700798
799 // Access the internal pid configuration to clear it out (unrelated to the
800 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800801 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700802
803 zone->addFanPID(std::move(tpid));
804
Patrick Venture563a3562018-10-30 09:31:26 -0700805 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
806 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
807 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700808
809 // Method under test will, for each fan PID, call setpt, input, and output.
Patrick Venture563a3562018-10-30 09:31:26 -0700810 zone->processFans();
Patrick Venturea58197c2018-06-11 15:29:45 -0700811}
812
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700813TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected)
814{
Patrick Venturea58197c2018-06-11 15:29:45 -0700815 // The manual(bool) method is inherited from the dbus mode interface.
816
817 // Verifies that someone doesn't remove the internal call to the dbus
818 // object from which we're inheriting.
819 EXPECT_CALL(sdbus_mock_mode,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700820 sd_bus_emit_properties_changed_strv(
821 IsNull(), StrEq(objPath), StrEq(modeInterface), NotNull()))
Harvey.Wua1ae4fa2022-10-28 17:38:35 +0800822 .WillOnce(Invoke(
823 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
824 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400825 EXPECT_STREQ("Manual", names[0]);
826 return 0;
827 }));
Patrick Venturea58197c2018-06-11 15:29:45 -0700828
829 // Method under test will set the manual mode to true and broadcast this
830 // change on dbus.
831 zone->manual(true);
832 EXPECT_TRUE(zone->getManualMode());
833}
834
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700835TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected)
836{
Patrick Venturea58197c2018-06-11 15:29:45 -0700837 // This property is implemented by us as read-only, such that trying to
838 // write to it will have no effect.
James Zheng6df8bb52024-11-27 23:38:47 +0000839
840 // Disable failsafe logger for the unit test.
841 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
842 buildFailsafeLoggers(empty_zone_map, 0);
843
Patrick Venturea58197c2018-06-11 15:29:45 -0700844 EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode());
845}
Patrick Venturea0764872020-08-08 07:48:43 -0700846
847} // namespace
848} // namespace pid_control