blob: e4e7a2697d65fec937feef535272385291d76f94 [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>
Patrick Williamse3c60772025-04-07 17:53:42 -040016#include <optional>
James Zheng6df8bb52024-11-27 23:38:47 +000017#include <unordered_map>
Patrick Venturea58197c2018-06-11 15:29:45 -070018#include <vector>
19
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070020#include <gmock/gmock.h>
21#include <gtest/gtest.h>
Patrick Venturea58197c2018-06-11 15:29:45 -070022
Patrick Venturea0764872020-08-08 07:48:43 -070023namespace pid_control
24{
25namespace
26{
27
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070028using ::testing::_;
Patrick Venturea58197c2018-06-11 15:29:45 -070029using ::testing::IsNull;
30using ::testing::Return;
31using ::testing::StrEq;
Patrick Venturea58197c2018-06-11 15:29:45 -070032
33static std::string modeInterface = "xyz.openbmc_project.Control.Mode";
Harvey Wucc0232a2023-02-09 14:58:55 +080034static std::string debugZoneInterface = "xyz.openbmc_project.Debug.Pid.Zone";
ykchiu7c6d35d2023-05-10 17:01:46 +080035static std::string enableInterface = "xyz.openbmc_project.Object.Enable";
Harvey Wu37180062023-10-02 09:42:50 +080036static std::string debugThermalPowerInterface =
37 "xyz.openbmc_project.Debug.Pid.ThermalPower";
Patrick Venturea58197c2018-06-11 15:29:45 -070038
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070039namespace
40{
Patrick Venturea58197c2018-06-11 15:29:45 -070041
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070042TEST(PidZoneConstructorTest, BoringConstructorTest)
43{
Patrick Venturea58197c2018-06-11 15:29:45 -070044 // Build a PID Zone.
45
ykchiu7c6d35d2023-05-10 17:01:46 +080046 sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode,
47 sdbus_mock_enable;
Patrick Venturea58197c2018-06-11 15:29:45 -070048 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
49 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
50 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
ykchiu7c6d35d2023-05-10 17:01:46 +080051 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
Patrick Venturea58197c2018-06-11 15:29:45 -070052
53 EXPECT_CALL(sdbus_mock_host,
54 sd_bus_add_object_manager(
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070055 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
Patrick Venturea58197c2018-06-11 15:29:45 -070056 .WillOnce(Return(0));
57
James Feist1fe08952019-05-07 09:17:16 -070058 SensorManager m(bus_mock_passive, bus_mock_host);
Patrick Venturea58197c2018-06-11 15:29:45 -070059
60 bool defer = true;
Delphine CC Chiu97889632023-11-06 11:32:46 +080061 bool accSetPoint = false;
Patrick Venturee2ec0f62018-09-04 12:30:27 -070062 const char* objPath = "/path/";
Patrick Venturea58197c2018-06-11 15:29:45 -070063 int64_t zone = 1;
James Feist3484bed2019-02-25 13:28:18 -080064 double minThermalOutput = 1000.0;
Harvey Wu92f9f3c2023-11-07 09:23:35 +080065 double failSafePercent = 100;
Bonnie Lo0e8fc392022-10-05 10:20:55 +080066 conf::CycleTime cycleTime;
Patrick Venturea58197c2018-06-11 15:29:45 -070067
James Feist0709e2f2020-07-08 10:59:45 -070068 double d;
Patrick Venturea58197c2018-06-11 15:29:45 -070069 std::vector<std::string> properties;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070070 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface, properties,
James Feist0709e2f2020-07-08 10:59:45 -070071 &d);
Harvey Wucc0232a2023-02-09 14:58:55 +080072 SetupDbusObject(&sdbus_mock_mode, defer, objPath, debugZoneInterface,
73 properties, &d);
Patrick Venturea58197c2018-06-11 15:29:45 -070074
ykchiu7c6d35d2023-05-10 17:01:46 +080075 std::string sensorname = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -040076 std::string pidsensorpath =
77 "/xyz/openbmc_project/settings/fanctrl/zone1/" + sensorname;
ykchiu7c6d35d2023-05-10 17:01:46 +080078
79 double de;
80 std::vector<std::string> propertiesenable;
81 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
82 enableInterface, propertiesenable, &de);
83
Bonnie Lo0e8fc392022-10-05 10:20:55 +080084 DbusPidZone p(zone, minThermalOutput, failSafePercent, cycleTime, m,
Delphine CC Chiu97889632023-11-06 11:32:46 +080085 bus_mock_mode, objPath, defer, accSetPoint);
Patrick Venturea58197c2018-06-11 15:29:45 -070086 // Success.
87}
88
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070089} // namespace
Patrick Venturea58197c2018-06-11 15:29:45 -070090
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070091class PidZoneTest : public ::testing::Test
92{
93 protected:
94 PidZoneTest() :
95 property_index(), properties(), sdbus_mock_passive(), sdbus_mock_host(),
ykchiu7c6d35d2023-05-10 17:01:46 +080096 sdbus_mock_mode(), sdbus_mock_enable()
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070097 {
98 EXPECT_CALL(sdbus_mock_host,
99 sd_bus_add_object_manager(
100 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
101 .WillOnce(Return(0));
Patrick Venturea58197c2018-06-11 15:29:45 -0700102
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700103 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
104 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
105 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
ykchiu7c6d35d2023-05-10 17:01:46 +0800106 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
Patrick Venturea58197c2018-06-11 15:29:45 -0700107
Patrick Williamse3c60772025-04-07 17:53:42 -0400108 mgr = SensorManager(bus_mock_passive, bus_mock_host);
Patrick Venturea58197c2018-06-11 15:29:45 -0700109
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700110 SetupDbusObject(&sdbus_mock_mode, defer, objPath, modeInterface,
111 properties, &property_index);
Harvey Wucc0232a2023-02-09 14:58:55 +0800112 SetupDbusObject(&sdbus_mock_mode, defer, objPath, debugZoneInterface,
113 properties, &property_index);
Patrick Venturea58197c2018-06-11 15:29:45 -0700114
ykchiu7c6d35d2023-05-10 17:01:46 +0800115 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
116 enableInterface, propertiesenable,
117 &propertyenable_index);
118
Delphine CC Chiu97889632023-11-06 11:32:46 +0800119 zone = std::make_unique<DbusPidZone>(
Patrick Williamse3c60772025-04-07 17:53:42 -0400120 zoneId, minThermalOutput, failSafePercent, cycleTime, *mgr,
Delphine CC Chiu97889632023-11-06 11:32:46 +0800121 bus_mock_mode, objPath, defer, accSetPoint);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700122 }
Patrick Venturea58197c2018-06-11 15:29:45 -0700123
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700124 // unused
James Feist0709e2f2020-07-08 10:59:45 -0700125 double property_index;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700126 std::vector<std::string> properties;
ykchiu7c6d35d2023-05-10 17:01:46 +0800127 double propertyenable_index;
128 std::vector<std::string> propertiesenable;
Patrick Venturea58197c2018-06-11 15:29:45 -0700129
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700130 sdbusplus::SdBusMock sdbus_mock_passive;
131 sdbusplus::SdBusMock sdbus_mock_host;
132 sdbusplus::SdBusMock sdbus_mock_mode;
ykchiu7c6d35d2023-05-10 17:01:46 +0800133 sdbusplus::SdBusMock sdbus_mock_enable;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700134 int64_t zoneId = 1;
James Feist3484bed2019-02-25 13:28:18 -0800135 double minThermalOutput = 1000.0;
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800136 double failSafePercent = 100;
Harvey Wu37180062023-10-02 09:42:50 +0800137 double setpoint = 50.0;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700138 bool defer = true;
Delphine CC Chiu97889632023-11-06 11:32:46 +0800139 bool accSetPoint = false;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700140 const char* objPath = "/path/";
Patrick Williamse3c60772025-04-07 17:53:42 -0400141 std::optional<SensorManager> mgr;
Bonnie Lo0e8fc392022-10-05 10:20:55 +0800142 conf::CycleTime cycleTime;
Patrick Venturea58197c2018-06-11 15:29:45 -0700143
ykchiu7c6d35d2023-05-10 17:01:46 +0800144 std::string sensorname = "temp1";
Harvey Wu37180062023-10-02 09:42:50 +0800145 std::string sensorType = "temp";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400146 std::string pidsensorpath =
147 "/xyz/openbmc_project/settings/fanctrl/zone1/" + sensorname;
ykchiu7c6d35d2023-05-10 17:01:46 +0800148
Patrick Venture597ebd62020-08-11 08:48:19 -0700149 std::unique_ptr<DbusPidZone> zone;
Patrick Venturea58197c2018-06-11 15:29:45 -0700150};
151
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700152TEST_F(PidZoneTest, GetZoneId_ReturnsExpected)
153{
Patrick Venturea58197c2018-06-11 15:29:45 -0700154 // Verifies the zoneId returned is what we expect.
155
Patrick Venture0bbeaf82018-10-30 18:50:31 -0700156 EXPECT_EQ(zoneId, zone->getZoneID());
Patrick Venturea58197c2018-06-11 15:29:45 -0700157}
158
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700159TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected)
160{
Patrick Venturea58197c2018-06-11 15:29:45 -0700161 // Verifies that the zone starts in manual mode. Verifies that one can set
162 // the mode.
163 EXPECT_FALSE(zone->getManualMode());
164
165 zone->setManualMode(true);
166 EXPECT_TRUE(zone->getManualMode());
167}
168
ykchiu7c6d35d2023-05-10 17:01:46 +0800169TEST_F(PidZoneTest, AddPidControlProcessGetAndSetEnableTest_BehavesAsExpected)
170{
171 // Verifies that the zone starts in enable mode. Verifies that one can set
172 // enable the mode.
173 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
174
175 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
176 IsNull(), StrEq(pidsensorpath.c_str()),
177 StrEq(enableInterface), NotNull()))
178 .Times(::testing::AnyNumber())
179 .WillOnce(Invoke(
180 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
181 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400182 EXPECT_STREQ("Enable", names[0]);
183 return 0;
184 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800185
Harvey Wu37180062023-10-02 09:42:50 +0800186 zone->addPidControlProcess(sensorname, sensorType, setpoint,
187 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800188 EXPECT_TRUE(zone->isPidProcessEnabled(sensorname));
189}
190
Josh Lehana4146eb2020-10-01 11:49:09 -0700191TEST_F(PidZoneTest, SetManualMode_RedundantWritesEnabledOnceAfterManualMode)
192{
193 // Tests adding a fan PID controller to the zone, and verifies it's
194 // touched during processing.
195
196 std::unique_ptr<PIDController> tpid =
197 std::make_unique<ControllerMock>("fan1", zone.get());
198 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
199
200 // Access the internal pid configuration to clear it out (unrelated to the
201 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800202 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Josh Lehana4146eb2020-10-01 11:49:09 -0700203
204 zone->addFanPID(std::move(tpid));
205
206 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
207 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
208 EXPECT_CALL(*tmock, outputProc(_));
209
210 // while zone is in auto mode redundant writes should be disabled
211 EXPECT_FALSE(zone->getRedundantWrite());
212
213 // but switching from manual to auto enables a single redundant write
214 zone->setManualMode(true);
215 zone->setManualMode(false);
216 EXPECT_TRUE(zone->getRedundantWrite());
217
218 // after one iteration of a pid loop redundant write should be cleared
219 zone->processFans();
220 EXPECT_FALSE(zone->getRedundantWrite());
221}
222
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700223TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected)
224{
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700225 // Tests addSetPoint, clearSetPoints, determineMaxSetPointRequest
Nirav Shahccc8bb62022-02-17 21:06:51 -0800226 // and getMinThermalSetPoint.
Patrick Venturea58197c2018-06-11 15:29:45 -0700227
ykchiu7c6d35d2023-05-10 17:01:46 +0800228 // Need to add pid control process for the zone that can enable
229 // the process and add the set point.
230 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
231
232 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
233 IsNull(), StrEq(pidsensorpath.c_str()),
234 StrEq(enableInterface), NotNull()))
235 .Times(::testing::AnyNumber())
236 .WillOnce(Invoke(
237 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
238 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400239 EXPECT_STREQ("Enable", names[0]);
240 return 0;
241 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800242
Harvey Wu37180062023-10-02 09:42:50 +0800243 zone->addPidControlProcess(sensorname, sensorType, setpoint,
244 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800245
Patrick Venturea58197c2018-06-11 15:29:45 -0700246 // At least one value must be above the minimum thermal setpoint used in
247 // the constructor otherwise it'll choose that value
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800248 std::vector<double> values = {100, 200, 300, 400, 500, 5000};
ykchiu7c6d35d2023-05-10 17:01:46 +0800249
Patrick Venturea58197c2018-06-11 15:29:45 -0700250 for (auto v : values)
251 {
ykchiu7c6d35d2023-05-10 17:01:46 +0800252 zone->addSetPoint(v, sensorname);
Patrick Venturea58197c2018-06-11 15:29:45 -0700253 }
254
255 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700256 zone->determineMaxSetPointRequest();
257 EXPECT_EQ(5000, zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700258
259 // Clear the values, so it'll choose the minimum thermal setpoint.
Patrick Venture9bbf3332019-07-16 10:50:37 -0700260 zone->clearSetPoints();
Patrick Venturea58197c2018-06-11 15:29:45 -0700261
262 // This will go through the RPM set point values and grab the maximum.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700263 zone->determineMaxSetPointRequest();
Nirav Shahccc8bb62022-02-17 21:06:51 -0800264 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700265}
266
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700267TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected)
268{
Patrick Venturea58197c2018-06-11 15:29:45 -0700269 // Tests adding several RPM setpoints, however, they're all lower than the
Patrick Venture7280e272019-02-11 10:45:32 -0800270 // configured minimal thermal setpoint RPM value.
Patrick Venturea58197c2018-06-11 15:29:45 -0700271
ykchiu7c6d35d2023-05-10 17:01:46 +0800272 // Need to add pid control process for the zone that can enable
273 // the process and add the set point.
274 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
275
276 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
277 IsNull(), StrEq(pidsensorpath.c_str()),
278 StrEq(enableInterface), NotNull()))
279 .Times(::testing::AnyNumber())
280 .WillOnce(Invoke(
281 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
282 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400283 EXPECT_STREQ("Enable", names[0]);
284 return 0;
285 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800286
Harvey Wu37180062023-10-02 09:42:50 +0800287 zone->addPidControlProcess(sensorname, sensorType, setpoint,
288 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800289
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800290 std::vector<double> values = {100, 200, 300, 400, 500};
ykchiu7c6d35d2023-05-10 17:01:46 +0800291
Patrick Venturea58197c2018-06-11 15:29:45 -0700292 for (auto v : values)
293 {
ykchiu7c6d35d2023-05-10 17:01:46 +0800294 zone->addSetPoint(v, sensorname);
Patrick Venturea58197c2018-06-11 15:29:45 -0700295 }
296
297 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700298 zone->determineMaxSetPointRequest();
Patrick Venturea58197c2018-06-11 15:29:45 -0700299
300 // Verifies the value returned in the minimal thermal rpm set point.
Nirav Shahccc8bb62022-02-17 21:06:51 -0800301 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700302}
303
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800304TEST_F(PidZoneTest, GetFailSafePercent_SingleFailedReturnsExpected)
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700305{
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800306 // Tests when only one sensor failed and the sensor's failsafe duty is zero,
307 // and verify that the sensor name is empty and failsafe duty is PID zone's
308 // failsafe duty.
ykchiu9fe3a3c2023-05-11 13:43:54 +0800309
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800310 std::vector<std::string> input1 = {"temp1"};
311 std::vector<std::string> input2 = {"temp2"};
312 std::vector<std::string> input3 = {"temp3"};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800313 std::vector<double> values = {0, 0, 0};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800314
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800315 zone->addPidFailSafePercent(input1, values[0]);
316 zone->addPidFailSafePercent(input2, values[1]);
317 zone->addPidFailSafePercent(input3, values[2]);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800318
Harvey Wua4270072024-05-29 16:11:13 +0800319 zone->markSensorMissing("temp1", "Sensor threshold asserted");
ykchiu9fe3a3c2023-05-11 13:43:54 +0800320
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800321 EXPECT_EQ(failSafePercent, zone->getFailSafePercent());
Harvey Wua4270072024-05-29 16:11:13 +0800322
323 std::map<std::string, std::pair<std::string, double>> failSensorList =
324 zone->getFailSafeSensors();
325 EXPECT_EQ(1, failSensorList.size());
326 EXPECT_EQ("Sensor threshold asserted", failSensorList["temp1"].first);
327 EXPECT_EQ(failSafePercent, failSensorList["temp1"].second);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800328}
329
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800330TEST_F(PidZoneTest, GetFailSafePercent_MultiFailedReturnsExpected)
ykchiu9fe3a3c2023-05-11 13:43:54 +0800331{
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800332 // Tests when multi sensor failed, and verify the final failsafe's sensor
333 // name and duty as expected.
ykchiu9fe3a3c2023-05-11 13:43:54 +0800334
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800335 std::vector<std::string> input1 = {"temp1"};
336 std::vector<std::string> input2 = {"temp2"};
337 std::vector<std::string> input3 = {"temp3"};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800338 std::vector<double> values = {60, 80, 70};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800339
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800340 zone->addPidFailSafePercent(input1, values[0]);
341 zone->addPidFailSafePercent(input2, values[1]);
342 zone->addPidFailSafePercent(input3, values[2]);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800343
Harvey Wua4270072024-05-29 16:11:13 +0800344 zone->markSensorMissing("temp1", "Sensor threshold asserted");
345 zone->markSensorMissing("temp2", "Sensor reading bad");
346 zone->markSensorMissing("temp3", "Sensor unavailable");
ykchiu9fe3a3c2023-05-11 13:43:54 +0800347
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800348 EXPECT_EQ(80, zone->getFailSafePercent());
Harvey Wua4270072024-05-29 16:11:13 +0800349
350 std::map<std::string, std::pair<std::string, double>> failSensorList =
351 zone->getFailSafeSensors();
352 EXPECT_EQ(3, failSensorList.size());
353 EXPECT_EQ("Sensor threshold asserted", failSensorList["temp1"].first);
354 EXPECT_EQ(60, failSensorList["temp1"].second);
355 EXPECT_EQ("Sensor reading bad", failSensorList["temp2"].first);
356 EXPECT_EQ(80, failSensorList["temp2"].second);
357 EXPECT_EQ("Sensor unavailable", failSensorList["temp3"].first);
358 EXPECT_EQ(70, failSensorList["temp3"].second);
Patrick Venturea58197c2018-06-11 15:29:45 -0700359}
360
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700361TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors)
362{
Patrick Venturea58197c2018-06-11 15:29:45 -0700363 // This test will add a couple thermal inputs, and verify that the zone
364 // initializes into failsafe mode, and will read each sensor.
365
James Zheng6df8bb52024-11-27 23:38:47 +0000366 // Disable failsafe logger for the unit test.
367 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
368 buildFailsafeLoggers(empty_zone_map, 0);
369
Patrick Venturea58197c2018-06-11 15:29:45 -0700370 std::string name1 = "temp1";
371 int64_t timeout = 1;
372
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400373 std::unique_ptr<Sensor> sensor1 =
374 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700375 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700376
377 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400378 std::unique_ptr<Sensor> sensor2 =
379 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700380 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700381
382 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400383 mgr->addSensor(type, name1, std::move(sensor1));
384 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
385 mgr->addSensor(type, name2, std::move(sensor2));
386 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Patrick Venturea58197c2018-06-11 15:29:45 -0700387
388 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800389 zone->addThermalInput(name1, false);
390 zone->addThermalInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700391
392 // Initialize Zone
393 zone->initializeCache();
394
395 // Verify now in failsafe mode.
396 EXPECT_TRUE(zone->getFailSafeMode());
397
398 ReadReturn r1;
399 r1.value = 10.0;
400 r1.updated = std::chrono::high_resolution_clock::now();
401 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
402
403 ReadReturn r2;
404 r2.value = 11.0;
405 r2.updated = std::chrono::high_resolution_clock::now();
406 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
407
408 // Read the sensors, this will put the values into the cache.
409 zone->updateSensors();
410
411 // We should no longer be in failsafe mode.
412 EXPECT_FALSE(zone->getFailSafeMode());
413
414 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
415 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
416}
417
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700418TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached)
419{
Patrick Venturea58197c2018-06-11 15:29:45 -0700420 // This will add a couple fan inputs, and verify the values are cached.
421
James Zheng6df8bb52024-11-27 23:38:47 +0000422 // Disable failsafe logger for the unit test.
423 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
424 buildFailsafeLoggers(empty_zone_map, 0);
425
Patrick Venturea58197c2018-06-11 15:29:45 -0700426 std::string name1 = "fan1";
427 int64_t timeout = 2;
428
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400429 std::unique_ptr<Sensor> sensor1 =
430 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700431 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700432
433 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400434 std::unique_ptr<Sensor> sensor2 =
435 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700436 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700437
438 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400439 mgr->addSensor(type, name1, std::move(sensor1));
440 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
441 mgr->addSensor(type, name2, std::move(sensor2));
442 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Patrick Venturea58197c2018-06-11 15:29:45 -0700443
444 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800445 zone->addFanInput(name1, false);
446 zone->addFanInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700447
448 // Initialize Zone
449 zone->initializeCache();
450
451 ReadReturn r1;
452 r1.value = 10.0;
453 r1.updated = std::chrono::high_resolution_clock::now();
454 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
455
456 ReadReturn r2;
457 r2.value = 11.0;
458 r2.updated = std::chrono::high_resolution_clock::now();
459 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
460
461 // Method under test will read through each fan sensor for the zone and
462 // cache the values.
463 zone->updateFanTelemetry();
464
465 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
466 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
467}
468
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700469TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode)
470{
Patrick Venturea58197c2018-06-11 15:29:45 -0700471 // On the second updateSensors call, the updated timestamp will be beyond
472 // the timeout limit.
473
James Zheng6df8bb52024-11-27 23:38:47 +0000474 // Disable failsafe logger for the unit test.
475 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
476 buildFailsafeLoggers(empty_zone_map, 0);
477
Patrick Venturea58197c2018-06-11 15:29:45 -0700478 int64_t timeout = 1;
479
480 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400481 std::unique_ptr<Sensor> sensor1 =
482 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700483 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700484
485 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400486 std::unique_ptr<Sensor> sensor2 =
487 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700488 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700489
490 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400491 mgr->addSensor(type, name1, std::move(sensor1));
492 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
493 mgr->addSensor(type, name2, std::move(sensor2));
494 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Patrick Venturea58197c2018-06-11 15:29:45 -0700495
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800496 zone->addThermalInput(name1, false);
497 zone->addThermalInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700498
499 // Initialize Zone
500 zone->initializeCache();
501
502 // Verify now in failsafe mode.
503 EXPECT_TRUE(zone->getFailSafeMode());
504
505 ReadReturn r1;
506 r1.value = 10.0;
507 r1.updated = std::chrono::high_resolution_clock::now();
508 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
509
510 ReadReturn r2;
511 r2.value = 11.0;
512 r2.updated = std::chrono::high_resolution_clock::now();
513 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
514
515 zone->updateSensors();
516 EXPECT_FALSE(zone->getFailSafeMode());
517
518 // Ok, so we're not in failsafe mode, so let's set updated to the past.
519 // sensor1 will have an updated field older than its timeout value, but
520 // sensor2 will be fine. :D
521 r1.updated -= std::chrono::seconds(3);
522 r2.updated = std::chrono::high_resolution_clock::now();
523
524 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
525 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
526
527 // Method under test will read each sensor. One sensor's value is older
528 // than the timeout for that sensor and this triggers failsafe mode.
529 zone->updateSensors();
530 EXPECT_TRUE(zone->getFailSafeMode());
531}
532
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800533TEST_F(PidZoneTest, ThermalInput_MissingIsAcceptableNoFailSafe)
534{
535 // This is similar to the above test, but because missingIsAcceptable
536 // is set for sensor1, the zone should not enter failsafe mode when
537 // only sensor1 goes missing.
538 // However, sensor2 going missing should still trigger failsafe mode.
539
James Zheng6df8bb52024-11-27 23:38:47 +0000540 // Disable failsafe logger for the unit test.
541 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
542 buildFailsafeLoggers(empty_zone_map, 0);
543
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800544 int64_t timeout = 1;
545
546 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400547 std::unique_ptr<Sensor> sensor1 =
548 std::make_unique<SensorMock>(name1, timeout);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800549 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
550
551 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400552 std::unique_ptr<Sensor> sensor2 =
553 std::make_unique<SensorMock>(name2, timeout);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800554 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
555
556 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400557 mgr->addSensor(type, name1, std::move(sensor1));
558 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
559 mgr->addSensor(type, name2, std::move(sensor2));
560 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800561
562 // Only sensor1 has MissingIsAcceptable enabled for it
563 zone->addThermalInput(name1, true);
564 zone->addThermalInput(name2, false);
565
566 // Initialize Zone
567 zone->initializeCache();
568
569 // As sensors are not initialized, zone should be in failsafe mode
570 EXPECT_TRUE(zone->getFailSafeMode());
571
572 // r1 not populated here, intentionally, to simulate a sensor that
573 // is not available yet, perhaps takes a long time to start up.
574 ReadReturn r1;
575 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
576
577 ReadReturn r2;
578 r2.value = 11.0;
579 r2.updated = std::chrono::high_resolution_clock::now();
580 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
581
582 zone->updateSensors();
583
584 // Only sensor2 has been initialized here. Failsafe should be false,
585 // because sensor1 MissingIsAcceptable so it is OK for it to go missing.
586 EXPECT_FALSE(zone->getFailSafeMode());
587
588 r1.value = 10.0;
589 r1.updated = std::chrono::high_resolution_clock::now();
590
591 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
592 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
593 zone->updateSensors();
594
595 // Both sensors are now properly initialized
596 EXPECT_FALSE(zone->getFailSafeMode());
597
598 // Ok, so we're not in failsafe mode, so let's set updated to the past.
599 // sensor1 will have an updated field older than its timeout value, but
600 // sensor2 will be fine. :D
601 r1.updated -= std::chrono::seconds(3);
602 r2.updated = std::chrono::high_resolution_clock::now();
603
604 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
605 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
606 zone->updateSensors();
607
608 // MissingIsAcceptable is true for sensor1, so the zone should not be
609 // thrown into failsafe mode.
610 EXPECT_FALSE(zone->getFailSafeMode());
611
612 // Do the same thing, but for the opposite sensors: r1 is good,
613 // but r2 is set to some time in the past.
614 r1.updated = std::chrono::high_resolution_clock::now();
615 r2.updated -= std::chrono::seconds(3);
616
617 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
618 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
619 zone->updateSensors();
620
621 // Now, the zone should be in failsafe mode, because sensor2 does not
622 // have MissingIsAcceptable set true, it is still subject to failsafe.
623 EXPECT_TRUE(zone->getFailSafeMode());
624
625 r1.updated = std::chrono::high_resolution_clock::now();
626 r2.updated = std::chrono::high_resolution_clock::now();
627
628 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
629 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
630 zone->updateSensors();
631
632 // The failsafe mode should cease, as both sensors are good again.
633 EXPECT_FALSE(zone->getFailSafeMode());
634}
635
Will Liangded0ab52019-05-15 17:10:06 +0800636TEST_F(PidZoneTest, FanInputTest_FailsafeToValid_ReadsSensors)
637{
638 // This will add a couple fan inputs, and verify the values are cached.
639
James Zheng6df8bb52024-11-27 23:38:47 +0000640 // Disable failsafe logger for the unit test.
641 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
642 buildFailsafeLoggers(empty_zone_map, 0);
643
Will Liangded0ab52019-05-15 17:10:06 +0800644 std::string name1 = "fan1";
645 int64_t timeout = 2;
646
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400647 std::unique_ptr<Sensor> sensor1 =
648 std::make_unique<SensorMock>(name1, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800649 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
650
651 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400652 std::unique_ptr<Sensor> sensor2 =
653 std::make_unique<SensorMock>(name2, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800654 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
655
656 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400657 mgr->addSensor(type, name1, std::move(sensor1));
658 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
659 mgr->addSensor(type, name2, std::move(sensor2));
660 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Will Liangded0ab52019-05-15 17:10:06 +0800661
662 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800663 zone->addFanInput(name1, false);
664 zone->addFanInput(name2, false);
Will Liangded0ab52019-05-15 17:10:06 +0800665
666 // Initialize Zone
667 zone->initializeCache();
668
669 // Verify now in failsafe mode.
670 EXPECT_TRUE(zone->getFailSafeMode());
671
672 ReadReturn r1;
673 r1.value = 10.0;
674 r1.updated = std::chrono::high_resolution_clock::now();
675 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
676
677 ReadReturn r2;
678 r2.value = 11.0;
679 r2.updated = std::chrono::high_resolution_clock::now();
680 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
681
682 // Method under test will read through each fan sensor for the zone and
683 // cache the values.
684 zone->updateFanTelemetry();
685
686 // We should no longer be in failsafe mode.
687 EXPECT_FALSE(zone->getFailSafeMode());
688
689 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
690 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
691}
692
693TEST_F(PidZoneTest, FanInputTest_ValueTimeoutEntersFailSafeMode)
694{
695 // This will add a couple fan inputs, and verify the values are cached.
696
James Zheng6df8bb52024-11-27 23:38:47 +0000697 // Disable failsafe logger for the unit test.
698 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
699 buildFailsafeLoggers(empty_zone_map, 0);
700
Will Liangded0ab52019-05-15 17:10:06 +0800701 std::string name1 = "fan1";
702 int64_t timeout = 2;
703
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400704 std::unique_ptr<Sensor> sensor1 =
705 std::make_unique<SensorMock>(name1, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800706 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
707
708 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400709 std::unique_ptr<Sensor> sensor2 =
710 std::make_unique<SensorMock>(name2, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800711 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
712
713 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400714 mgr->addSensor(type, name1, std::move(sensor1));
715 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
716 mgr->addSensor(type, name2, std::move(sensor2));
717 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Will Liangded0ab52019-05-15 17:10:06 +0800718
719 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800720 zone->addFanInput(name1, false);
721 zone->addFanInput(name2, false);
Will Liangded0ab52019-05-15 17:10:06 +0800722
723 // Initialize Zone
724 zone->initializeCache();
725
726 // Verify now in failsafe mode.
727 EXPECT_TRUE(zone->getFailSafeMode());
728
729 ReadReturn r1;
730 r1.value = 10.0;
731 r1.updated = std::chrono::high_resolution_clock::now();
732 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
733
734 ReadReturn r2;
735 r2.value = 11.0;
736 r2.updated = std::chrono::high_resolution_clock::now();
737 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
738
739 // Method under test will read through each fan sensor for the zone and
740 // cache the values.
741 zone->updateFanTelemetry();
742
743 // We should no longer be in failsafe mode.
744 EXPECT_FALSE(zone->getFailSafeMode());
745
746 r1.updated -= std::chrono::seconds(3);
747 r2.updated = std::chrono::high_resolution_clock::now();
748
749 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
750 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
751
752 zone->updateFanTelemetry();
753 EXPECT_TRUE(zone->getFailSafeMode());
754}
755
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700756TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected)
757{
Patrick Venturea58197c2018-06-11 15:29:45 -0700758 // One can grab a sensor from the manager through the zone.
759
James Zheng6df8bb52024-11-27 23:38:47 +0000760 // Disable failsafe logger for the unit test.
761 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
762 buildFailsafeLoggers(empty_zone_map, 0);
763
Patrick Venturea58197c2018-06-11 15:29:45 -0700764 int64_t timeout = 1;
765
766 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400767 std::unique_ptr<Sensor> sensor1 =
768 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700769 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700770
771 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400772 mgr->addSensor(type, name1, std::move(sensor1));
773 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
Patrick Venturea58197c2018-06-11 15:29:45 -0700774
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800775 zone->addThermalInput(name1, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700776
777 // Verify method under test returns the pointer we expect.
Patrick Williamse3c60772025-04-07 17:53:42 -0400778 EXPECT_EQ(mgr->getSensor(name1), zone->getSensor(name1));
Patrick Venturea58197c2018-06-11 15:29:45 -0700779}
780
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700781TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed)
782{
Patrick Venturea58197c2018-06-11 15:29:45 -0700783 // Tests adding a thermal PID controller to the zone, and verifies it's
784 // touched during processing.
785
786 std::unique_ptr<PIDController> tpid =
787 std::make_unique<ControllerMock>("thermal1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700788 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700789
790 // Access the internal pid configuration to clear it out (unrelated to the
791 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800792 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700793
794 zone->addThermalPID(std::move(tpid));
795
Patrick Venture563a3562018-10-30 09:31:26 -0700796 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
797 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
798 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700799
800 // Method under test will, for each thermal PID, call setpt, input, and
801 // output.
Patrick Venture563a3562018-10-30 09:31:26 -0700802 zone->processThermals();
Patrick Venturea58197c2018-06-11 15:29:45 -0700803}
804
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700805TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed)
806{
Patrick Venturea58197c2018-06-11 15:29:45 -0700807 // Tests adding a fan PID controller to the zone, and verifies it's
808 // touched during processing.
809
810 std::unique_ptr<PIDController> tpid =
811 std::make_unique<ControllerMock>("fan1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700812 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700813
814 // Access the internal pid configuration to clear it out (unrelated to the
815 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800816 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700817
818 zone->addFanPID(std::move(tpid));
819
Patrick Venture563a3562018-10-30 09:31:26 -0700820 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
821 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
822 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700823
824 // Method under test will, for each fan PID, call setpt, input, and output.
Patrick Venture563a3562018-10-30 09:31:26 -0700825 zone->processFans();
Patrick Venturea58197c2018-06-11 15:29:45 -0700826}
827
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700828TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected)
829{
Patrick Venturea58197c2018-06-11 15:29:45 -0700830 // The manual(bool) method is inherited from the dbus mode interface.
831
832 // Verifies that someone doesn't remove the internal call to the dbus
833 // object from which we're inheriting.
834 EXPECT_CALL(sdbus_mock_mode,
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700835 sd_bus_emit_properties_changed_strv(
836 IsNull(), StrEq(objPath), StrEq(modeInterface), NotNull()))
Harvey.Wua1ae4fa2022-10-28 17:38:35 +0800837 .WillOnce(Invoke(
838 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
839 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400840 EXPECT_STREQ("Manual", names[0]);
841 return 0;
842 }));
Patrick Venturea58197c2018-06-11 15:29:45 -0700843
844 // Method under test will set the manual mode to true and broadcast this
845 // change on dbus.
846 zone->manual(true);
847 EXPECT_TRUE(zone->getManualMode());
848}
849
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700850TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected)
851{
Patrick Venturea58197c2018-06-11 15:29:45 -0700852 // This property is implemented by us as read-only, such that trying to
853 // write to it will have no effect.
James Zheng6df8bb52024-11-27 23:38:47 +0000854
855 // Disable failsafe logger for the unit test.
856 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
857 buildFailsafeLoggers(empty_zone_map, 0);
858
Patrick Venturea58197c2018-06-11 15:29:45 -0700859 EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode());
860}
Patrick Venturea0764872020-08-08 07:48:43 -0700861
862} // namespace
863} // namespace pid_control