blob: c3daf470b5f06b1c5fb124835f4211f8c218e55c [file] [log] [blame]
Ed Tanousf8b6e552025-06-27 13:27:50 -07001#include "conf.hpp"
James Zheng6df8bb52024-11-27 23:38:47 +00002#include "failsafeloggers/builder.hpp"
Ed Tanousf8b6e552025-06-27 13:27:50 -07003#include "interfaces.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07004#include "pid/ec/pid.hpp"
Ed Tanousf8b6e552025-06-27 13:27:50 -07005#include "pid/pidcontroller.hpp"
Patrick Venturea58197c2018-06-11 15:29:45 -07006#include "pid/zone.hpp"
Ed Tanousf8b6e552025-06-27 13:27:50 -07007#include "pid/zone_interface.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07008#include "sensors/manager.hpp"
Ed Tanousf8b6e552025-06-27 13:27:50 -07009#include "sensors/sensor.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070010#include "test/controller_mock.hpp"
11#include "test/helpers.hpp"
12#include "test/sensor_mock.hpp"
Patrick Venturea58197c2018-06-11 15:29:45 -070013
Ed Tanousf8b6e552025-06-27 13:27:50 -070014#include <systemd/sd-bus.h>
15
Patrick Venturea83a3ec2020-08-04 09:52:05 -070016#include <sdbusplus/test/sdbus_mock.hpp>
Alexander Hansene907a812025-10-28 14:27:32 +010017#include <xyz/openbmc_project/Control/Mode/common.hpp>
18#include <xyz/openbmc_project/Debug/Pid/ThermalPower/common.hpp>
19#include <xyz/openbmc_project/Debug/Pid/Zone/common.hpp>
20#include <xyz/openbmc_project/Object/Enable/common.hpp>
Patrick Venturea83a3ec2020-08-04 09:52:05 -070021
Patrick Venturea58197c2018-06-11 15:29:45 -070022#include <chrono>
Ed Tanousf8b6e552025-06-27 13:27:50 -070023#include <cstdint>
Patrick Venturea58197c2018-06-11 15:29:45 -070024#include <cstring>
Ed Tanousf8b6e552025-06-27 13:27:50 -070025#include <map>
26#include <memory>
Patrick Williamse3c60772025-04-07 17:53:42 -040027#include <optional>
Ed Tanousf8b6e552025-06-27 13:27:50 -070028#include <string>
James Zheng6df8bb52024-11-27 23:38:47 +000029#include <unordered_map>
Ed Tanousf8b6e552025-06-27 13:27:50 -070030#include <utility>
Patrick Venturea58197c2018-06-11 15:29:45 -070031#include <vector>
32
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070033#include <gmock/gmock.h>
34#include <gtest/gtest.h>
Patrick Venturea58197c2018-06-11 15:29:45 -070035
Patrick Venturea0764872020-08-08 07:48:43 -070036namespace pid_control
37{
38namespace
39{
40
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070041using ::testing::_;
Patrick Venturea58197c2018-06-11 15:29:45 -070042using ::testing::IsNull;
43using ::testing::Return;
44using ::testing::StrEq;
Patrick Venturea58197c2018-06-11 15:29:45 -070045
Alexander Hansene907a812025-10-28 14:27:32 +010046using ControlMode = sdbusplus::common::xyz::openbmc_project::control::Mode;
47using DebugPidZone = sdbusplus::common::xyz::openbmc_project::debug::pid::Zone;
48using DebugThermalPower =
49 sdbusplus::common::xyz::openbmc_project::debug::pid::ThermalPower;
50using ObjectEnable = sdbusplus::common::xyz::openbmc_project::object::Enable;
Patrick Venturea58197c2018-06-11 15:29:45 -070051
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070052namespace
53{
Patrick Venturea58197c2018-06-11 15:29:45 -070054
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070055TEST(PidZoneConstructorTest, BoringConstructorTest)
56{
Patrick Venturea58197c2018-06-11 15:29:45 -070057 // Build a PID Zone.
58
ykchiu7c6d35d2023-05-10 17:01:46 +080059 sdbusplus::SdBusMock sdbus_mock_passive, sdbus_mock_host, sdbus_mock_mode,
60 sdbus_mock_enable;
Patrick Venturea58197c2018-06-11 15:29:45 -070061 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
62 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
63 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
ykchiu7c6d35d2023-05-10 17:01:46 +080064 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
Patrick Venturea58197c2018-06-11 15:29:45 -070065
66 EXPECT_CALL(sdbus_mock_host,
67 sd_bus_add_object_manager(
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070068 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
Patrick Venturea58197c2018-06-11 15:29:45 -070069 .WillOnce(Return(0));
70
James Feist1fe08952019-05-07 09:17:16 -070071 SensorManager m(bus_mock_passive, bus_mock_host);
Patrick Venturea58197c2018-06-11 15:29:45 -070072
73 bool defer = true;
Delphine CC Chiu97889632023-11-06 11:32:46 +080074 bool accSetPoint = false;
Patrick Venturee2ec0f62018-09-04 12:30:27 -070075 const char* objPath = "/path/";
Patrick Venturea58197c2018-06-11 15:29:45 -070076 int64_t zone = 1;
James Feist3484bed2019-02-25 13:28:18 -080077 double minThermalOutput = 1000.0;
Harvey Wu92f9f3c2023-11-07 09:23:35 +080078 double failSafePercent = 100;
Bonnie Lo0e8fc392022-10-05 10:20:55 +080079 conf::CycleTime cycleTime;
Patrick Venturea58197c2018-06-11 15:29:45 -070080
James Feist0709e2f2020-07-08 10:59:45 -070081 double d;
Patrick Venturea58197c2018-06-11 15:29:45 -070082 std::vector<std::string> properties;
Alexander Hansene907a812025-10-28 14:27:32 +010083 SetupDbusObject(&sdbus_mock_mode, defer, objPath, ControlMode::interface,
84 properties, &d);
85 SetupDbusObject(&sdbus_mock_mode, defer, objPath, DebugPidZone::interface,
Harvey Wucc0232a2023-02-09 14:58:55 +080086 properties, &d);
Patrick Venturea58197c2018-06-11 15:29:45 -070087
ykchiu7c6d35d2023-05-10 17:01:46 +080088 std::string sensorname = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -040089 std::string pidsensorpath =
90 "/xyz/openbmc_project/settings/fanctrl/zone1/" + sensorname;
ykchiu7c6d35d2023-05-10 17:01:46 +080091
92 double de;
93 std::vector<std::string> propertiesenable;
94 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
Alexander Hansene907a812025-10-28 14:27:32 +010095 ObjectEnable::interface, propertiesenable, &de);
ykchiu7c6d35d2023-05-10 17:01:46 +080096
Bonnie Lo0e8fc392022-10-05 10:20:55 +080097 DbusPidZone p(zone, minThermalOutput, failSafePercent, cycleTime, m,
Delphine CC Chiu97889632023-11-06 11:32:46 +080098 bus_mock_mode, objPath, defer, accSetPoint);
Patrick Venturea58197c2018-06-11 15:29:45 -070099 // Success.
100}
101
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700102} // namespace
Patrick Venturea58197c2018-06-11 15:29:45 -0700103
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700104class PidZoneTest : public ::testing::Test
105{
106 protected:
107 PidZoneTest() :
Ed Tanousd2768c52025-06-26 11:42:57 -0700108 properties(), sdbus_mock_passive(), sdbus_mock_host(),
ykchiu7c6d35d2023-05-10 17:01:46 +0800109 sdbus_mock_mode(), sdbus_mock_enable()
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700110 {
111 EXPECT_CALL(sdbus_mock_host,
112 sd_bus_add_object_manager(
113 IsNull(), _, StrEq("/xyz/openbmc_project/extsensors")))
114 .WillOnce(Return(0));
Patrick Venturea58197c2018-06-11 15:29:45 -0700115
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700116 auto bus_mock_passive = sdbusplus::get_mocked_new(&sdbus_mock_passive);
117 auto bus_mock_host = sdbusplus::get_mocked_new(&sdbus_mock_host);
118 auto bus_mock_mode = sdbusplus::get_mocked_new(&sdbus_mock_mode);
ykchiu7c6d35d2023-05-10 17:01:46 +0800119 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
Patrick Venturea58197c2018-06-11 15:29:45 -0700120
Patrick Williamse3c60772025-04-07 17:53:42 -0400121 mgr = SensorManager(bus_mock_passive, bus_mock_host);
Patrick Venturea58197c2018-06-11 15:29:45 -0700122
Alexander Hansene907a812025-10-28 14:27:32 +0100123 SetupDbusObject(&sdbus_mock_mode, defer, objPath,
124 ControlMode::interface, properties, &property_index);
125 SetupDbusObject(&sdbus_mock_mode, defer, objPath,
126 DebugPidZone::interface, properties, &property_index);
Patrick Venturea58197c2018-06-11 15:29:45 -0700127
ykchiu7c6d35d2023-05-10 17:01:46 +0800128 SetupDbusObject(&sdbus_mock_enable, defer, pidsensorpath.c_str(),
Alexander Hansene907a812025-10-28 14:27:32 +0100129 ObjectEnable::interface, propertiesenable,
ykchiu7c6d35d2023-05-10 17:01:46 +0800130 &propertyenable_index);
131
Delphine CC Chiu97889632023-11-06 11:32:46 +0800132 zone = std::make_unique<DbusPidZone>(
Patrick Williamse3c60772025-04-07 17:53:42 -0400133 zoneId, minThermalOutput, failSafePercent, cycleTime, *mgr,
Delphine CC Chiu97889632023-11-06 11:32:46 +0800134 bus_mock_mode, objPath, defer, accSetPoint);
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700135 }
Patrick Venturea58197c2018-06-11 15:29:45 -0700136
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700137 // unused
Ed Tanousd2768c52025-06-26 11:42:57 -0700138 double property_index{};
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700139 std::vector<std::string> properties;
ykchiu7c6d35d2023-05-10 17:01:46 +0800140 double propertyenable_index;
141 std::vector<std::string> propertiesenable;
Patrick Venturea58197c2018-06-11 15:29:45 -0700142
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700143 sdbusplus::SdBusMock sdbus_mock_passive;
144 sdbusplus::SdBusMock sdbus_mock_host;
145 sdbusplus::SdBusMock sdbus_mock_mode;
ykchiu7c6d35d2023-05-10 17:01:46 +0800146 sdbusplus::SdBusMock sdbus_mock_enable;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700147 int64_t zoneId = 1;
James Feist3484bed2019-02-25 13:28:18 -0800148 double minThermalOutput = 1000.0;
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800149 double failSafePercent = 100;
Harvey Wu37180062023-10-02 09:42:50 +0800150 double setpoint = 50.0;
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700151 bool defer = true;
Delphine CC Chiu97889632023-11-06 11:32:46 +0800152 bool accSetPoint = false;
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700153 const char* objPath = "/path/";
Patrick Williamse3c60772025-04-07 17:53:42 -0400154 std::optional<SensorManager> mgr;
Bonnie Lo0e8fc392022-10-05 10:20:55 +0800155 conf::CycleTime cycleTime;
Patrick Venturea58197c2018-06-11 15:29:45 -0700156
ykchiu7c6d35d2023-05-10 17:01:46 +0800157 std::string sensorname = "temp1";
Harvey Wu37180062023-10-02 09:42:50 +0800158 std::string sensorType = "temp";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400159 std::string pidsensorpath =
160 "/xyz/openbmc_project/settings/fanctrl/zone1/" + sensorname;
ykchiu7c6d35d2023-05-10 17:01:46 +0800161
Patrick Venture597ebd62020-08-11 08:48:19 -0700162 std::unique_ptr<DbusPidZone> zone;
Patrick Venturea58197c2018-06-11 15:29:45 -0700163};
164
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700165TEST_F(PidZoneTest, GetZoneId_ReturnsExpected)
166{
Patrick Venturea58197c2018-06-11 15:29:45 -0700167 // Verifies the zoneId returned is what we expect.
168
Patrick Venture0bbeaf82018-10-30 18:50:31 -0700169 EXPECT_EQ(zoneId, zone->getZoneID());
Patrick Venturea58197c2018-06-11 15:29:45 -0700170}
171
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700172TEST_F(PidZoneTest, GetAndSetManualModeTest_BehavesAsExpected)
173{
Patrick Venturea58197c2018-06-11 15:29:45 -0700174 // Verifies that the zone starts in manual mode. Verifies that one can set
175 // the mode.
176 EXPECT_FALSE(zone->getManualMode());
177
178 zone->setManualMode(true);
179 EXPECT_TRUE(zone->getManualMode());
180}
181
ykchiu7c6d35d2023-05-10 17:01:46 +0800182TEST_F(PidZoneTest, AddPidControlProcessGetAndSetEnableTest_BehavesAsExpected)
183{
184 // Verifies that the zone starts in enable mode. Verifies that one can set
185 // enable the mode.
186 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
187
188 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
189 IsNull(), StrEq(pidsensorpath.c_str()),
Alexander Hansene907a812025-10-28 14:27:32 +0100190 StrEq(ObjectEnable::interface), NotNull()))
ykchiu7c6d35d2023-05-10 17:01:46 +0800191 .Times(::testing::AnyNumber())
192 .WillOnce(Invoke(
193 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
194 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400195 EXPECT_STREQ("Enable", names[0]);
196 return 0;
197 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800198
Harvey Wu37180062023-10-02 09:42:50 +0800199 zone->addPidControlProcess(sensorname, sensorType, setpoint,
200 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800201 EXPECT_TRUE(zone->isPidProcessEnabled(sensorname));
202}
203
Josh Lehana4146eb2020-10-01 11:49:09 -0700204TEST_F(PidZoneTest, SetManualMode_RedundantWritesEnabledOnceAfterManualMode)
205{
206 // Tests adding a fan PID controller to the zone, and verifies it's
207 // touched during processing.
208
209 std::unique_ptr<PIDController> tpid =
210 std::make_unique<ControllerMock>("fan1", zone.get());
211 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
212
213 // Access the internal pid configuration to clear it out (unrelated to the
214 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800215 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Josh Lehana4146eb2020-10-01 11:49:09 -0700216
217 zone->addFanPID(std::move(tpid));
218
219 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
220 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
221 EXPECT_CALL(*tmock, outputProc(_));
222
223 // while zone is in auto mode redundant writes should be disabled
224 EXPECT_FALSE(zone->getRedundantWrite());
225
226 // but switching from manual to auto enables a single redundant write
227 zone->setManualMode(true);
228 zone->setManualMode(false);
229 EXPECT_TRUE(zone->getRedundantWrite());
230
231 // after one iteration of a pid loop redundant write should be cleared
232 zone->processFans();
233 EXPECT_FALSE(zone->getRedundantWrite());
234}
235
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700236TEST_F(PidZoneTest, RpmSetPoints_AddMaxClear_BehaveAsExpected)
237{
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700238 // Tests addSetPoint, clearSetPoints, determineMaxSetPointRequest
Nirav Shahccc8bb62022-02-17 21:06:51 -0800239 // and getMinThermalSetPoint.
Patrick Venturea58197c2018-06-11 15:29:45 -0700240
ykchiu7c6d35d2023-05-10 17:01:46 +0800241 // Need to add pid control process for the zone that can enable
242 // the process and add the set point.
243 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
244
245 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
246 IsNull(), StrEq(pidsensorpath.c_str()),
Alexander Hansene907a812025-10-28 14:27:32 +0100247 StrEq(ObjectEnable::interface), NotNull()))
ykchiu7c6d35d2023-05-10 17:01:46 +0800248 .Times(::testing::AnyNumber())
249 .WillOnce(Invoke(
250 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
251 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400252 EXPECT_STREQ("Enable", names[0]);
253 return 0;
254 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800255
Harvey Wu37180062023-10-02 09:42:50 +0800256 zone->addPidControlProcess(sensorname, sensorType, setpoint,
257 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800258
Patrick Venturea58197c2018-06-11 15:29:45 -0700259 // At least one value must be above the minimum thermal setpoint used in
260 // the constructor otherwise it'll choose that value
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800261 std::vector<double> values = {100, 200, 300, 400, 500, 5000};
ykchiu7c6d35d2023-05-10 17:01:46 +0800262
Patrick Venturea58197c2018-06-11 15:29:45 -0700263 for (auto v : values)
264 {
ykchiu7c6d35d2023-05-10 17:01:46 +0800265 zone->addSetPoint(v, sensorname);
Patrick Venturea58197c2018-06-11 15:29:45 -0700266 }
267
268 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700269 zone->determineMaxSetPointRequest();
270 EXPECT_EQ(5000, zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700271
272 // Clear the values, so it'll choose the minimum thermal setpoint.
Patrick Venture9bbf3332019-07-16 10:50:37 -0700273 zone->clearSetPoints();
Patrick Venturea58197c2018-06-11 15:29:45 -0700274
275 // This will go through the RPM set point values and grab the maximum.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700276 zone->determineMaxSetPointRequest();
Nirav Shahccc8bb62022-02-17 21:06:51 -0800277 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700278}
279
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700280TEST_F(PidZoneTest, RpmSetPoints_AddBelowMinimum_BehavesAsExpected)
281{
Patrick Venturea58197c2018-06-11 15:29:45 -0700282 // Tests adding several RPM setpoints, however, they're all lower than the
Patrick Venture7280e272019-02-11 10:45:32 -0800283 // configured minimal thermal setpoint RPM value.
Patrick Venturea58197c2018-06-11 15:29:45 -0700284
ykchiu7c6d35d2023-05-10 17:01:46 +0800285 // Need to add pid control process for the zone that can enable
286 // the process and add the set point.
287 auto bus_mock_enable = sdbusplus::get_mocked_new(&sdbus_mock_enable);
288
289 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
290 IsNull(), StrEq(pidsensorpath.c_str()),
Alexander Hansene907a812025-10-28 14:27:32 +0100291 StrEq(ObjectEnable::interface), NotNull()))
ykchiu7c6d35d2023-05-10 17:01:46 +0800292 .Times(::testing::AnyNumber())
293 .WillOnce(Invoke(
294 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
295 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400296 EXPECT_STREQ("Enable", names[0]);
297 return 0;
298 }));
ykchiu7c6d35d2023-05-10 17:01:46 +0800299
Harvey Wu37180062023-10-02 09:42:50 +0800300 zone->addPidControlProcess(sensorname, sensorType, setpoint,
301 bus_mock_enable, pidsensorpath.c_str(), defer);
ykchiu7c6d35d2023-05-10 17:01:46 +0800302
Patrick Venture5f59c0f2018-11-11 12:55:14 -0800303 std::vector<double> values = {100, 200, 300, 400, 500};
ykchiu7c6d35d2023-05-10 17:01:46 +0800304
Patrick Venturea58197c2018-06-11 15:29:45 -0700305 for (auto v : values)
306 {
ykchiu7c6d35d2023-05-10 17:01:46 +0800307 zone->addSetPoint(v, sensorname);
Patrick Venturea58197c2018-06-11 15:29:45 -0700308 }
309
310 // This will pull the maximum RPM setpoint request.
Patrick Venturef7a2dd52019-07-16 14:31:13 -0700311 zone->determineMaxSetPointRequest();
Patrick Venturea58197c2018-06-11 15:29:45 -0700312
313 // Verifies the value returned in the minimal thermal rpm set point.
Nirav Shahccc8bb62022-02-17 21:06:51 -0800314 EXPECT_EQ(zone->getMinThermalSetPoint(), zone->getMaxSetPointRequest());
Patrick Venturea58197c2018-06-11 15:29:45 -0700315}
316
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800317TEST_F(PidZoneTest, GetFailSafePercent_SingleFailedReturnsExpected)
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700318{
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800319 // Tests when only one sensor failed and the sensor's failsafe duty is zero,
320 // and verify that the sensor name is empty and failsafe duty is PID zone's
321 // failsafe duty.
ykchiu9fe3a3c2023-05-11 13:43:54 +0800322
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800323 std::vector<std::string> input1 = {"temp1"};
324 std::vector<std::string> input2 = {"temp2"};
325 std::vector<std::string> input3 = {"temp3"};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800326 std::vector<double> values = {0, 0, 0};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800327
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800328 zone->addPidFailSafePercent(input1, values[0]);
329 zone->addPidFailSafePercent(input2, values[1]);
330 zone->addPidFailSafePercent(input3, values[2]);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800331
Harvey Wua4270072024-05-29 16:11:13 +0800332 zone->markSensorMissing("temp1", "Sensor threshold asserted");
ykchiu9fe3a3c2023-05-11 13:43:54 +0800333
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800334 EXPECT_EQ(failSafePercent, zone->getFailSafePercent());
Harvey Wua4270072024-05-29 16:11:13 +0800335
336 std::map<std::string, std::pair<std::string, double>> failSensorList =
337 zone->getFailSafeSensors();
Ed Tanousd2768c52025-06-26 11:42:57 -0700338 EXPECT_EQ(1U, failSensorList.size());
Harvey Wua4270072024-05-29 16:11:13 +0800339 EXPECT_EQ("Sensor threshold asserted", failSensorList["temp1"].first);
340 EXPECT_EQ(failSafePercent, failSensorList["temp1"].second);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800341}
342
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800343TEST_F(PidZoneTest, GetFailSafePercent_MultiFailedReturnsExpected)
ykchiu9fe3a3c2023-05-11 13:43:54 +0800344{
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800345 // Tests when multi sensor failed, and verify the final failsafe's sensor
346 // name and duty as expected.
ykchiu9fe3a3c2023-05-11 13:43:54 +0800347
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800348 std::vector<std::string> input1 = {"temp1"};
349 std::vector<std::string> input2 = {"temp2"};
350 std::vector<std::string> input3 = {"temp3"};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800351 std::vector<double> values = {60, 80, 70};
ykchiu9fe3a3c2023-05-11 13:43:54 +0800352
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800353 zone->addPidFailSafePercent(input1, values[0]);
354 zone->addPidFailSafePercent(input2, values[1]);
355 zone->addPidFailSafePercent(input3, values[2]);
ykchiu9fe3a3c2023-05-11 13:43:54 +0800356
Harvey Wua4270072024-05-29 16:11:13 +0800357 zone->markSensorMissing("temp1", "Sensor threshold asserted");
358 zone->markSensorMissing("temp2", "Sensor reading bad");
359 zone->markSensorMissing("temp3", "Sensor unavailable");
ykchiu9fe3a3c2023-05-11 13:43:54 +0800360
Harvey Wu92f9f3c2023-11-07 09:23:35 +0800361 EXPECT_EQ(80, zone->getFailSafePercent());
Harvey Wua4270072024-05-29 16:11:13 +0800362
363 std::map<std::string, std::pair<std::string, double>> failSensorList =
364 zone->getFailSafeSensors();
Ed Tanousd2768c52025-06-26 11:42:57 -0700365 EXPECT_EQ(3U, failSensorList.size());
Harvey Wua4270072024-05-29 16:11:13 +0800366 EXPECT_EQ("Sensor threshold asserted", failSensorList["temp1"].first);
367 EXPECT_EQ(60, failSensorList["temp1"].second);
368 EXPECT_EQ("Sensor reading bad", failSensorList["temp2"].first);
369 EXPECT_EQ(80, failSensorList["temp2"].second);
370 EXPECT_EQ("Sensor unavailable", failSensorList["temp3"].first);
371 EXPECT_EQ(70, failSensorList["temp3"].second);
Patrick Venturea58197c2018-06-11 15:29:45 -0700372}
373
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700374TEST_F(PidZoneTest, ThermalInputs_FailsafeToValid_ReadsSensors)
375{
Patrick Venturea58197c2018-06-11 15:29:45 -0700376 // This test will add a couple thermal inputs, and verify that the zone
377 // initializes into failsafe mode, and will read each sensor.
378
James Zheng6df8bb52024-11-27 23:38:47 +0000379 // Disable failsafe logger for the unit test.
380 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
381 buildFailsafeLoggers(empty_zone_map, 0);
382
Patrick Venturea58197c2018-06-11 15:29:45 -0700383 std::string name1 = "temp1";
384 int64_t timeout = 1;
385
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400386 std::unique_ptr<Sensor> sensor1 =
387 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700388 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700389
390 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400391 std::unique_ptr<Sensor> sensor2 =
392 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700393 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700394
395 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400396 mgr->addSensor(type, name1, std::move(sensor1));
397 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
398 mgr->addSensor(type, name2, std::move(sensor2));
399 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Patrick Venturea58197c2018-06-11 15:29:45 -0700400
401 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800402 zone->addThermalInput(name1, false);
403 zone->addThermalInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700404
405 // Initialize Zone
406 zone->initializeCache();
407
408 // Verify now in failsafe mode.
409 EXPECT_TRUE(zone->getFailSafeMode());
410
411 ReadReturn r1;
412 r1.value = 10.0;
413 r1.updated = std::chrono::high_resolution_clock::now();
414 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
415
416 ReadReturn r2;
417 r2.value = 11.0;
418 r2.updated = std::chrono::high_resolution_clock::now();
419 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
420
421 // Read the sensors, this will put the values into the cache.
422 zone->updateSensors();
423
424 // We should no longer be in failsafe mode.
425 EXPECT_FALSE(zone->getFailSafeMode());
426
427 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
428 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
429}
430
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700431TEST_F(PidZoneTest, FanInputTest_VerifiesFanValuesCached)
432{
Patrick Venturea58197c2018-06-11 15:29:45 -0700433 // This will add a couple fan inputs, and verify the values are cached.
434
James Zheng6df8bb52024-11-27 23:38:47 +0000435 // Disable failsafe logger for the unit test.
436 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
437 buildFailsafeLoggers(empty_zone_map, 0);
438
Patrick Venturea58197c2018-06-11 15:29:45 -0700439 std::string name1 = "fan1";
440 int64_t timeout = 2;
441
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400442 std::unique_ptr<Sensor> sensor1 =
443 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700444 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700445
446 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400447 std::unique_ptr<Sensor> sensor2 =
448 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700449 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700450
451 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400452 mgr->addSensor(type, name1, std::move(sensor1));
453 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
454 mgr->addSensor(type, name2, std::move(sensor2));
455 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Patrick Venturea58197c2018-06-11 15:29:45 -0700456
457 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800458 zone->addFanInput(name1, false);
459 zone->addFanInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700460
461 // Initialize Zone
462 zone->initializeCache();
463
464 ReadReturn r1;
465 r1.value = 10.0;
466 r1.updated = std::chrono::high_resolution_clock::now();
467 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
468
469 ReadReturn r2;
470 r2.value = 11.0;
471 r2.updated = std::chrono::high_resolution_clock::now();
472 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
473
474 // Method under test will read through each fan sensor for the zone and
475 // cache the values.
476 zone->updateFanTelemetry();
477
478 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
479 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
480}
481
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700482TEST_F(PidZoneTest, ThermalInput_ValueTimeoutEntersFailSafeMode)
483{
Patrick Venturea58197c2018-06-11 15:29:45 -0700484 // On the second updateSensors call, the updated timestamp will be beyond
485 // the timeout limit.
486
James Zheng6df8bb52024-11-27 23:38:47 +0000487 // Disable failsafe logger for the unit test.
488 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
489 buildFailsafeLoggers(empty_zone_map, 0);
490
Patrick Venturea58197c2018-06-11 15:29:45 -0700491 int64_t timeout = 1;
492
493 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400494 std::unique_ptr<Sensor> sensor1 =
495 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700496 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700497
498 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400499 std::unique_ptr<Sensor> sensor2 =
500 std::make_unique<SensorMock>(name2, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700501 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700502
503 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400504 mgr->addSensor(type, name1, std::move(sensor1));
505 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
506 mgr->addSensor(type, name2, std::move(sensor2));
507 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Patrick Venturea58197c2018-06-11 15:29:45 -0700508
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800509 zone->addThermalInput(name1, false);
510 zone->addThermalInput(name2, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700511
512 // Initialize Zone
513 zone->initializeCache();
514
515 // Verify now in failsafe mode.
516 EXPECT_TRUE(zone->getFailSafeMode());
517
518 ReadReturn r1;
519 r1.value = 10.0;
520 r1.updated = std::chrono::high_resolution_clock::now();
521 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
522
523 ReadReturn r2;
524 r2.value = 11.0;
525 r2.updated = std::chrono::high_resolution_clock::now();
526 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
527
528 zone->updateSensors();
529 EXPECT_FALSE(zone->getFailSafeMode());
530
531 // Ok, so we're not in failsafe mode, so let's set updated to the past.
532 // sensor1 will have an updated field older than its timeout value, but
533 // sensor2 will be fine. :D
534 r1.updated -= std::chrono::seconds(3);
535 r2.updated = std::chrono::high_resolution_clock::now();
536
537 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
538 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
539
540 // Method under test will read each sensor. One sensor's value is older
541 // than the timeout for that sensor and this triggers failsafe mode.
542 zone->updateSensors();
543 EXPECT_TRUE(zone->getFailSafeMode());
544}
545
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800546TEST_F(PidZoneTest, ThermalInput_MissingIsAcceptableNoFailSafe)
547{
548 // This is similar to the above test, but because missingIsAcceptable
549 // is set for sensor1, the zone should not enter failsafe mode when
550 // only sensor1 goes missing.
551 // However, sensor2 going missing should still trigger failsafe mode.
552
James Zheng6df8bb52024-11-27 23:38:47 +0000553 // Disable failsafe logger for the unit test.
554 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
555 buildFailsafeLoggers(empty_zone_map, 0);
556
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800557 int64_t timeout = 1;
558
559 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400560 std::unique_ptr<Sensor> sensor1 =
561 std::make_unique<SensorMock>(name1, timeout);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800562 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
563
564 std::string name2 = "temp2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400565 std::unique_ptr<Sensor> sensor2 =
566 std::make_unique<SensorMock>(name2, timeout);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800567 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
568
569 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400570 mgr->addSensor(type, name1, std::move(sensor1));
571 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
572 mgr->addSensor(type, name2, std::move(sensor2));
573 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800574
575 // Only sensor1 has MissingIsAcceptable enabled for it
576 zone->addThermalInput(name1, true);
577 zone->addThermalInput(name2, false);
578
579 // Initialize Zone
580 zone->initializeCache();
581
582 // As sensors are not initialized, zone should be in failsafe mode
583 EXPECT_TRUE(zone->getFailSafeMode());
584
585 // r1 not populated here, intentionally, to simulate a sensor that
586 // is not available yet, perhaps takes a long time to start up.
587 ReadReturn r1;
588 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
589
590 ReadReturn r2;
591 r2.value = 11.0;
592 r2.updated = std::chrono::high_resolution_clock::now();
593 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
594
595 zone->updateSensors();
596
597 // Only sensor2 has been initialized here. Failsafe should be false,
598 // because sensor1 MissingIsAcceptable so it is OK for it to go missing.
599 EXPECT_FALSE(zone->getFailSafeMode());
600
601 r1.value = 10.0;
602 r1.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 // Both sensors are now properly initialized
609 EXPECT_FALSE(zone->getFailSafeMode());
610
611 // Ok, so we're not in failsafe mode, so let's set updated to the past.
612 // sensor1 will have an updated field older than its timeout value, but
613 // sensor2 will be fine. :D
614 r1.updated -= std::chrono::seconds(3);
615 r2.updated = std::chrono::high_resolution_clock::now();
616
617 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
618 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
619 zone->updateSensors();
620
621 // MissingIsAcceptable is true for sensor1, so the zone should not be
622 // thrown into failsafe mode.
623 EXPECT_FALSE(zone->getFailSafeMode());
624
625 // Do the same thing, but for the opposite sensors: r1 is good,
626 // but r2 is set to some time in the past.
627 r1.updated = std::chrono::high_resolution_clock::now();
628 r2.updated -= std::chrono::seconds(3);
629
630 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
631 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
632 zone->updateSensors();
633
634 // Now, the zone should be in failsafe mode, because sensor2 does not
635 // have MissingIsAcceptable set true, it is still subject to failsafe.
636 EXPECT_TRUE(zone->getFailSafeMode());
637
638 r1.updated = std::chrono::high_resolution_clock::now();
639 r2.updated = std::chrono::high_resolution_clock::now();
640
641 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
642 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
643 zone->updateSensors();
644
645 // The failsafe mode should cease, as both sensors are good again.
646 EXPECT_FALSE(zone->getFailSafeMode());
647}
648
Will Liangded0ab52019-05-15 17:10:06 +0800649TEST_F(PidZoneTest, FanInputTest_FailsafeToValid_ReadsSensors)
650{
651 // This will add a couple fan inputs, and verify the values are cached.
652
James Zheng6df8bb52024-11-27 23:38:47 +0000653 // Disable failsafe logger for the unit test.
654 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
655 buildFailsafeLoggers(empty_zone_map, 0);
656
Will Liangded0ab52019-05-15 17:10:06 +0800657 std::string name1 = "fan1";
658 int64_t timeout = 2;
659
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400660 std::unique_ptr<Sensor> sensor1 =
661 std::make_unique<SensorMock>(name1, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800662 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
663
664 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400665 std::unique_ptr<Sensor> sensor2 =
666 std::make_unique<SensorMock>(name2, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800667 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
668
669 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400670 mgr->addSensor(type, name1, std::move(sensor1));
671 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
672 mgr->addSensor(type, name2, std::move(sensor2));
673 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Will Liangded0ab52019-05-15 17:10:06 +0800674
675 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800676 zone->addFanInput(name1, false);
677 zone->addFanInput(name2, false);
Will Liangded0ab52019-05-15 17:10:06 +0800678
679 // Initialize Zone
680 zone->initializeCache();
681
682 // Verify now in failsafe mode.
683 EXPECT_TRUE(zone->getFailSafeMode());
684
685 ReadReturn r1;
686 r1.value = 10.0;
687 r1.updated = std::chrono::high_resolution_clock::now();
688 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
689
690 ReadReturn r2;
691 r2.value = 11.0;
692 r2.updated = std::chrono::high_resolution_clock::now();
693 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
694
695 // Method under test will read through each fan sensor for the zone and
696 // cache the values.
697 zone->updateFanTelemetry();
698
699 // We should no longer be in failsafe mode.
700 EXPECT_FALSE(zone->getFailSafeMode());
701
702 EXPECT_EQ(r1.value, zone->getCachedValue(name1));
703 EXPECT_EQ(r2.value, zone->getCachedValue(name2));
704}
705
706TEST_F(PidZoneTest, FanInputTest_ValueTimeoutEntersFailSafeMode)
707{
708 // This will add a couple fan inputs, and verify the values are cached.
709
James Zheng6df8bb52024-11-27 23:38:47 +0000710 // Disable failsafe logger for the unit test.
711 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
712 buildFailsafeLoggers(empty_zone_map, 0);
713
Will Liangded0ab52019-05-15 17:10:06 +0800714 std::string name1 = "fan1";
715 int64_t timeout = 2;
716
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400717 std::unique_ptr<Sensor> sensor1 =
718 std::make_unique<SensorMock>(name1, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800719 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
720
721 std::string name2 = "fan2";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400722 std::unique_ptr<Sensor> sensor2 =
723 std::make_unique<SensorMock>(name2, timeout);
Will Liangded0ab52019-05-15 17:10:06 +0800724 SensorMock* sensor_ptr2 = reinterpret_cast<SensorMock*>(sensor2.get());
725
726 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400727 mgr->addSensor(type, name1, std::move(sensor1));
728 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
729 mgr->addSensor(type, name2, std::move(sensor2));
730 EXPECT_EQ(mgr->getSensor(name2), sensor_ptr2);
Will Liangded0ab52019-05-15 17:10:06 +0800731
732 // Now that the sensors exist, add them to the zone.
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800733 zone->addFanInput(name1, false);
734 zone->addFanInput(name2, false);
Will Liangded0ab52019-05-15 17:10:06 +0800735
736 // Initialize Zone
737 zone->initializeCache();
738
739 // Verify now in failsafe mode.
740 EXPECT_TRUE(zone->getFailSafeMode());
741
742 ReadReturn r1;
743 r1.value = 10.0;
744 r1.updated = std::chrono::high_resolution_clock::now();
745 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
746
747 ReadReturn r2;
748 r2.value = 11.0;
749 r2.updated = std::chrono::high_resolution_clock::now();
750 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
751
752 // Method under test will read through each fan sensor for the zone and
753 // cache the values.
754 zone->updateFanTelemetry();
755
756 // We should no longer be in failsafe mode.
757 EXPECT_FALSE(zone->getFailSafeMode());
758
759 r1.updated -= std::chrono::seconds(3);
760 r2.updated = std::chrono::high_resolution_clock::now();
761
762 EXPECT_CALL(*sensor_ptr1, read()).WillOnce(Return(r1));
763 EXPECT_CALL(*sensor_ptr2, read()).WillOnce(Return(r2));
764
765 zone->updateFanTelemetry();
766 EXPECT_TRUE(zone->getFailSafeMode());
767}
768
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700769TEST_F(PidZoneTest, GetSensorTest_ReturnsExpected)
770{
Patrick Venturea58197c2018-06-11 15:29:45 -0700771 // One can grab a sensor from the manager through the zone.
772
James Zheng6df8bb52024-11-27 23:38:47 +0000773 // Disable failsafe logger for the unit test.
774 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
775 buildFailsafeLoggers(empty_zone_map, 0);
776
Patrick Venturea58197c2018-06-11 15:29:45 -0700777 int64_t timeout = 1;
778
779 std::string name1 = "temp1";
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400780 std::unique_ptr<Sensor> sensor1 =
781 std::make_unique<SensorMock>(name1, timeout);
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700782 SensorMock* sensor_ptr1 = reinterpret_cast<SensorMock*>(sensor1.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700783
784 std::string type = "unchecked";
Patrick Williamse3c60772025-04-07 17:53:42 -0400785 mgr->addSensor(type, name1, std::move(sensor1));
786 EXPECT_EQ(mgr->getSensor(name1), sensor_ptr1);
Patrick Venturea58197c2018-06-11 15:29:45 -0700787
Josh Lehan3f0f7bc2023-02-13 01:45:29 -0800788 zone->addThermalInput(name1, false);
Patrick Venturea58197c2018-06-11 15:29:45 -0700789
790 // Verify method under test returns the pointer we expect.
Patrick Williamse3c60772025-04-07 17:53:42 -0400791 EXPECT_EQ(mgr->getSensor(name1), zone->getSensor(name1));
Patrick Venturea58197c2018-06-11 15:29:45 -0700792}
793
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700794TEST_F(PidZoneTest, AddThermalPIDTest_VerifiesThermalPIDsProcessed)
795{
Patrick Venturea58197c2018-06-11 15:29:45 -0700796 // Tests adding a thermal PID controller to the zone, and verifies it's
797 // touched during processing.
798
799 std::unique_ptr<PIDController> tpid =
800 std::make_unique<ControllerMock>("thermal1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700801 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700802
803 // Access the internal pid configuration to clear it out (unrelated to the
804 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800805 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700806
807 zone->addThermalPID(std::move(tpid));
808
Patrick Venture563a3562018-10-30 09:31:26 -0700809 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
810 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
811 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700812
813 // Method under test will, for each thermal PID, call setpt, input, and
814 // output.
Patrick Venture563a3562018-10-30 09:31:26 -0700815 zone->processThermals();
Patrick Venturea58197c2018-06-11 15:29:45 -0700816}
817
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700818TEST_F(PidZoneTest, AddFanPIDTest_VerifiesFanPIDsProcessed)
819{
Patrick Venturea58197c2018-06-11 15:29:45 -0700820 // Tests adding a fan PID controller to the zone, and verifies it's
821 // touched during processing.
822
823 std::unique_ptr<PIDController> tpid =
824 std::make_unique<ControllerMock>("fan1", zone.get());
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700825 ControllerMock* tmock = reinterpret_cast<ControllerMock*>(tpid.get());
Patrick Venturea58197c2018-06-11 15:29:45 -0700826
827 // Access the internal pid configuration to clear it out (unrelated to the
828 // test).
Harvey Wu1b3b7302024-10-04 16:49:46 +0800829 [[maybe_unused]] ec::pid_info_t* info = tpid->getPIDInfo();
Patrick Venturea58197c2018-06-11 15:29:45 -0700830
831 zone->addFanPID(std::move(tpid));
832
Patrick Venture563a3562018-10-30 09:31:26 -0700833 EXPECT_CALL(*tmock, setptProc()).WillOnce(Return(10.0));
834 EXPECT_CALL(*tmock, inputProc()).WillOnce(Return(11.0));
835 EXPECT_CALL(*tmock, outputProc(_));
Patrick Venturea58197c2018-06-11 15:29:45 -0700836
837 // Method under test will, for each fan PID, call setpt, input, and output.
Patrick Venture563a3562018-10-30 09:31:26 -0700838 zone->processFans();
Patrick Venturea58197c2018-06-11 15:29:45 -0700839}
840
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700841TEST_F(PidZoneTest, ManualModeDbusTest_VerifySetManualBehavesAsExpected)
842{
Patrick Venturea58197c2018-06-11 15:29:45 -0700843 // The manual(bool) method is inherited from the dbus mode interface.
844
845 // Verifies that someone doesn't remove the internal call to the dbus
846 // object from which we're inheriting.
Alexander Hansene907a812025-10-28 14:27:32 +0100847 EXPECT_CALL(sdbus_mock_mode, sd_bus_emit_properties_changed_strv(
848 IsNull(), StrEq(objPath),
849 StrEq(ControlMode::interface), NotNull()))
Harvey.Wua1ae4fa2022-10-28 17:38:35 +0800850 .WillOnce(Invoke(
851 [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
852 [[maybe_unused]] const char* interface, const char** names) {
Patrick Williamsbd63bca2024-08-16 15:21:10 -0400853 EXPECT_STREQ("Manual", names[0]);
854 return 0;
855 }));
Patrick Venturea58197c2018-06-11 15:29:45 -0700856
857 // Method under test will set the manual mode to true and broadcast this
858 // change on dbus.
859 zone->manual(true);
860 EXPECT_TRUE(zone->getManualMode());
861}
862
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700863TEST_F(PidZoneTest, FailsafeDbusTest_VerifiesReturnsExpected)
864{
Patrick Venturea58197c2018-06-11 15:29:45 -0700865 // This property is implemented by us as read-only, such that trying to
866 // write to it will have no effect.
James Zheng6df8bb52024-11-27 23:38:47 +0000867
868 // Disable failsafe logger for the unit test.
869 std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> empty_zone_map;
870 buildFailsafeLoggers(empty_zone_map, 0);
871
Patrick Venturea58197c2018-06-11 15:29:45 -0700872 EXPECT_EQ(zone->failSafe(), zone->getFailSafeMode());
873}
Patrick Venturea0764872020-08-08 07:48:43 -0700874
875} // namespace
876} // namespace pid_control