xref: /openbmc/phosphor-pid-control/test/pid_thermalcontroller_unittest.cpp (revision bd63bcaca2ac9edf1778136cf240e3bbe8b31566)
131058fd3SJosh Lehan #include "conf.hpp"
2de74542cSJosh Lehan #include "pid/ec/logging.hpp"
3da4a5dd1SPatrick Venture #include "pid/ec/pid.hpp"
43349ef20SPatrick Venture #include "pid/thermalcontroller.hpp"
5da4a5dd1SPatrick Venture #include "test/zone_mock.hpp"
63349ef20SPatrick Venture 
73349ef20SPatrick Venture #include <string>
83349ef20SPatrick Venture #include <vector>
93349ef20SPatrick Venture 
10da4a5dd1SPatrick Venture #include <gmock/gmock.h>
11da4a5dd1SPatrick Venture #include <gtest/gtest.h>
123349ef20SPatrick Venture 
13a076487aSPatrick Venture namespace pid_control
14a076487aSPatrick Venture {
15a076487aSPatrick Venture namespace
16a076487aSPatrick Venture {
17a076487aSPatrick Venture 
18572c43daSJames Feist using ::testing::_;
193349ef20SPatrick Venture using ::testing::Return;
203349ef20SPatrick Venture using ::testing::StrEq;
213349ef20SPatrick Venture 
TEST(ThermalControllerTest,BoringFactoryTest)22da4a5dd1SPatrick Venture TEST(ThermalControllerTest, BoringFactoryTest)
23da4a5dd1SPatrick Venture {
243349ef20SPatrick Venture     // Verifies building a ThermalPIDController with the factory works as
253349ef20SPatrick Venture     // expected in the boring (uninteresting) case.
263349ef20SPatrick Venture 
273349ef20SPatrick Venture     ZoneMock z;
283349ef20SPatrick Venture 
2931058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
305f59c0fdSPatrick Venture     double setpoint = 10.0;
313349ef20SPatrick Venture     ec::pidinfo initial;
323349ef20SPatrick Venture 
33563a356fSPatrick Venture     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
34734f9535SJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
353349ef20SPatrick Venture     // Success
363349ef20SPatrick Venture     EXPECT_FALSE(p == nullptr);
373349ef20SPatrick Venture }
383349ef20SPatrick Venture 
TEST(ThermalControllerTest,VerifyFactoryFailsWithZeroInputs)39da4a5dd1SPatrick Venture TEST(ThermalControllerTest, VerifyFactoryFailsWithZeroInputs)
40da4a5dd1SPatrick Venture {
413349ef20SPatrick Venture     // A thermal controller needs at least one input.
423349ef20SPatrick Venture 
433349ef20SPatrick Venture     ZoneMock z;
443349ef20SPatrick Venture 
4531058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {};
465f59c0fdSPatrick Venture     double setpoint = 10.0;
473349ef20SPatrick Venture     ec::pidinfo initial;
48734f9535SJames Feist     std::unique_ptr<PIDController> p;
49734f9535SJames Feist     EXPECT_THROW(
50da4a5dd1SPatrick Venture         {
51734f9535SJames Feist             p = ThermalController::createThermalPid(
52734f9535SJames Feist                 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
53734f9535SJames Feist         },
54734f9535SJames Feist         std::exception);
553349ef20SPatrick Venture     EXPECT_TRUE(p == nullptr);
563349ef20SPatrick Venture }
573349ef20SPatrick Venture 
TEST(ThermalControllerTest,InputProc_BehavesAsExpected)58da4a5dd1SPatrick Venture TEST(ThermalControllerTest, InputProc_BehavesAsExpected)
59da4a5dd1SPatrick Venture {
60563a356fSPatrick Venture     // This test just verifies inputProc behaves as expected.
613349ef20SPatrick Venture 
623349ef20SPatrick Venture     ZoneMock z;
633349ef20SPatrick Venture 
6431058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
655f59c0fdSPatrick Venture     double setpoint = 10.0;
663349ef20SPatrick Venture     ec::pidinfo initial;
673349ef20SPatrick Venture 
68563a356fSPatrick Venture     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
69734f9535SJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
703349ef20SPatrick Venture     EXPECT_FALSE(p == nullptr);
713349ef20SPatrick Venture 
723349ef20SPatrick Venture     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
733349ef20SPatrick Venture 
74563a356fSPatrick Venture     EXPECT_EQ(5.0, p->inputProc());
753349ef20SPatrick Venture }
763349ef20SPatrick Venture 
TEST(ThermalControllerTest,SetPtProc_BehavesAsExpected)77da4a5dd1SPatrick Venture TEST(ThermalControllerTest, SetPtProc_BehavesAsExpected)
78da4a5dd1SPatrick Venture {
79563a356fSPatrick Venture     // This test just verifies inputProc behaves as expected.
803349ef20SPatrick Venture 
813349ef20SPatrick Venture     ZoneMock z;
823349ef20SPatrick Venture 
8331058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
845f59c0fdSPatrick Venture     double setpoint = 10.0;
853349ef20SPatrick Venture     ec::pidinfo initial;
863349ef20SPatrick Venture 
87563a356fSPatrick Venture     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
88734f9535SJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
893349ef20SPatrick Venture     EXPECT_FALSE(p == nullptr);
903349ef20SPatrick Venture 
91563a356fSPatrick Venture     EXPECT_EQ(setpoint, p->setptProc());
923349ef20SPatrick Venture }
933349ef20SPatrick Venture 
TEST(ThermalControllerTest,OutputProc_BehavesAsExpected)94da4a5dd1SPatrick Venture TEST(ThermalControllerTest, OutputProc_BehavesAsExpected)
95da4a5dd1SPatrick Venture {
96734f9535SJames Feist     // This test just verifies outputProc behaves as expected.
973349ef20SPatrick Venture 
983349ef20SPatrick Venture     ZoneMock z;
993349ef20SPatrick Venture 
10031058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
1015f59c0fdSPatrick Venture     double setpoint = 10.0;
1023349ef20SPatrick Venture     ec::pidinfo initial;
1033349ef20SPatrick Venture 
104563a356fSPatrick Venture     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
105734f9535SJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
1063349ef20SPatrick Venture     EXPECT_FALSE(p == nullptr);
1073349ef20SPatrick Venture 
1085f59c0fdSPatrick Venture     double value = 90.0;
109ccc8bb62SNirav Shah     EXPECT_CALL(z, addSetPoint(value, "therm1"));
1103349ef20SPatrick Venture 
111563a356fSPatrick Venture     p->outputProc(value);
1123349ef20SPatrick Venture }
113734f9535SJames Feist 
TEST(ThermalControllerTest,InputProc_MultipleInputsAbsolute)114734f9535SJames Feist TEST(ThermalControllerTest, InputProc_MultipleInputsAbsolute)
115734f9535SJames Feist {
116734f9535SJames Feist     // This test verifies inputProc behaves as expected with multiple absolute
117734f9535SJames Feist     // inputs.
118734f9535SJames Feist 
119734f9535SJames Feist     ZoneMock z;
120734f9535SJames Feist 
121*bd63bcacSPatrick Williams     std::vector<pid_control::conf::SensorInput> inputs = {
122*bd63bcacSPatrick Williams         {"fleeting0"}, {"fleeting1"}};
123734f9535SJames Feist     double setpoint = 10.0;
124734f9535SJames Feist     ec::pidinfo initial;
125734f9535SJames Feist 
126734f9535SJames Feist     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
127734f9535SJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::absolute);
128734f9535SJames Feist     EXPECT_FALSE(p == nullptr);
129734f9535SJames Feist 
130734f9535SJames Feist     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
131734f9535SJames Feist     EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
132734f9535SJames Feist 
133734f9535SJames Feist     EXPECT_EQ(10.0, p->inputProc());
134734f9535SJames Feist }
135734f9535SJames Feist 
TEST(ThermalControllerTest,InputProc_MultipleInputsMargin)136734f9535SJames Feist TEST(ThermalControllerTest, InputProc_MultipleInputsMargin)
137734f9535SJames Feist {
138734f9535SJames Feist     // This test verifies inputProc behaves as expected with multiple margin
139734f9535SJames Feist     // inputs.
140734f9535SJames Feist 
141734f9535SJames Feist     ZoneMock z;
142734f9535SJames Feist 
143*bd63bcacSPatrick Williams     std::vector<pid_control::conf::SensorInput> inputs = {
144*bd63bcacSPatrick Williams         {"fleeting0"}, {"fleeting1"}};
145734f9535SJames Feist     double setpoint = 10.0;
146734f9535SJames Feist     ec::pidinfo initial;
147734f9535SJames Feist 
148734f9535SJames Feist     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
149734f9535SJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
150734f9535SJames Feist     EXPECT_FALSE(p == nullptr);
151734f9535SJames Feist 
152734f9535SJames Feist     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
153734f9535SJames Feist     EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
154734f9535SJames Feist 
155734f9535SJames Feist     EXPECT_EQ(5.0, p->inputProc());
156734f9535SJames Feist }
157572c43daSJames Feist 
TEST(ThermalControllerTest,InputProc_MultipleInputsSummation)15823e22b90SJosh Lehan TEST(ThermalControllerTest, InputProc_MultipleInputsSummation)
15923e22b90SJosh Lehan {
16023e22b90SJosh Lehan     // This test verifies inputProc behaves as expected with multiple summation
16123e22b90SJosh Lehan     // inputs.
16223e22b90SJosh Lehan 
16323e22b90SJosh Lehan     ZoneMock z;
16423e22b90SJosh Lehan 
165*bd63bcacSPatrick Williams     std::vector<pid_control::conf::SensorInput> inputs = {
166*bd63bcacSPatrick Williams         {"fleeting0"}, {"fleeting1"}};
16723e22b90SJosh Lehan     double setpoint = 10.0;
16823e22b90SJosh Lehan     ec::pidinfo initial;
16923e22b90SJosh Lehan 
17023e22b90SJosh Lehan     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
17123e22b90SJosh Lehan         &z, "therm1", inputs, setpoint, initial, ThermalType::summation);
17223e22b90SJosh Lehan     EXPECT_FALSE(p == nullptr);
17323e22b90SJosh Lehan 
17423e22b90SJosh Lehan     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
17523e22b90SJosh Lehan     EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
17623e22b90SJosh Lehan 
17723e22b90SJosh Lehan     EXPECT_EQ(15.0, p->inputProc());
17823e22b90SJosh Lehan }
17923e22b90SJosh Lehan 
TEST(ThermalControllerTest,InputProc_MultipleInputsTempToMargin)18031058fd3SJosh Lehan TEST(ThermalControllerTest, InputProc_MultipleInputsTempToMargin)
18131058fd3SJosh Lehan {
18231058fd3SJosh Lehan     // This test verifies inputProc behaves as expected with multiple margin
18331058fd3SJosh Lehan     // inputs and TempToMargin in use.
18431058fd3SJosh Lehan 
18531058fd3SJosh Lehan     ZoneMock z;
18631058fd3SJosh Lehan 
18731058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {
18831058fd3SJosh Lehan         {"absolute0", 85.0, true}, {"margin1"}};
18931058fd3SJosh Lehan     double setpoint = 10.0;
19031058fd3SJosh Lehan     ec::pidinfo initial;
19131058fd3SJosh Lehan 
19231058fd3SJosh Lehan     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
19331058fd3SJosh Lehan         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
19431058fd3SJosh Lehan     EXPECT_FALSE(p == nullptr);
19531058fd3SJosh Lehan 
19631058fd3SJosh Lehan     EXPECT_CALL(z, getCachedValue(StrEq("absolute0"))).WillOnce(Return(82.0));
19731058fd3SJosh Lehan     EXPECT_CALL(z, getCachedValue(StrEq("margin1"))).WillOnce(Return(5.0));
19831058fd3SJosh Lehan 
19931058fd3SJosh Lehan     // 82 degrees temp, 85 degrees Tjmax => 3 degrees of safety margin
20031058fd3SJosh Lehan     EXPECT_EQ(3.0, p->inputProc());
20131058fd3SJosh Lehan }
20231058fd3SJosh Lehan 
TEST(ThermalControllerTest,NegHysteresis_BehavesAsExpected)203572c43daSJames Feist TEST(ThermalControllerTest, NegHysteresis_BehavesAsExpected)
204572c43daSJames Feist {
205572c43daSJames Feist     // This test verifies Negative hysteresis behaves as expected by
206572c43daSJames Feist     // crossing the setpoint and noticing readings don't change until past the
207572c43daSJames Feist     // hysteresis value
208572c43daSJames Feist 
209572c43daSJames Feist     ZoneMock z;
210572c43daSJames Feist 
21131058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
212572c43daSJames Feist     double setpoint = 10.0;
213572c43daSJames Feist     ec::pidinfo initial;
2149788963cSDelphine CC Chiu     initial.checkHysterWithSetpt = false;
215572c43daSJames Feist     initial.negativeHysteresis = 4.0;
216572c43daSJames Feist 
217572c43daSJames Feist     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
218572c43daSJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
219572c43daSJames Feist     EXPECT_FALSE(p == nullptr);
220572c43daSJames Feist 
221572c43daSJames Feist     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0")))
222572c43daSJames Feist         .Times(3)
223572c43daSJames Feist         .WillOnce(Return(12.0))
224572c43daSJames Feist         .WillOnce(Return(9.0))
225572c43daSJames Feist         .WillOnce(Return(7.0));
226572c43daSJames Feist 
227ccc8bb62SNirav Shah     EXPECT_CALL(z, addSetPoint(_, "therm1")).Times(3);
228572c43daSJames Feist 
229572c43daSJames Feist     std::vector<double> lastReadings = {12.0, 12.0, 7.0};
230572c43daSJames Feist     for (auto& reading : lastReadings)
231572c43daSJames Feist     {
232572c43daSJames Feist         p->process();
233572c43daSJames Feist         EXPECT_EQ(p->getLastInput(), reading);
234572c43daSJames Feist     }
235572c43daSJames Feist }
236572c43daSJames Feist 
TEST(ThermalControllerTest,PosHysteresis_BehavesAsExpected)237572c43daSJames Feist TEST(ThermalControllerTest, PosHysteresis_BehavesAsExpected)
238572c43daSJames Feist {
239572c43daSJames Feist     // This test verifies Positive hysteresis behaves as expected by
240572c43daSJames Feist     // crossing the setpoint and noticing readings don't change until past the
241572c43daSJames Feist     // hysteresis value
242572c43daSJames Feist 
243572c43daSJames Feist     ZoneMock z;
244572c43daSJames Feist 
24531058fd3SJosh Lehan     std::vector<pid_control::conf::SensorInput> inputs = {{"fleeting0"}};
246572c43daSJames Feist     double setpoint = 10.0;
247572c43daSJames Feist     ec::pidinfo initial;
2489788963cSDelphine CC Chiu     initial.checkHysterWithSetpt = false;
249572c43daSJames Feist     initial.positiveHysteresis = 5.0;
250572c43daSJames Feist 
251572c43daSJames Feist     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
252572c43daSJames Feist         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
253572c43daSJames Feist     EXPECT_FALSE(p == nullptr);
254572c43daSJames Feist 
255572c43daSJames Feist     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0")))
256572c43daSJames Feist         .Times(3)
257572c43daSJames Feist         .WillOnce(Return(8.0))
258572c43daSJames Feist         .WillOnce(Return(13.0))
259572c43daSJames Feist         .WillOnce(Return(14.0));
260572c43daSJames Feist 
261ccc8bb62SNirav Shah     EXPECT_CALL(z, addSetPoint(_, "therm1")).Times(3);
262572c43daSJames Feist 
263572c43daSJames Feist     std::vector<double> lastReadings = {8.0, 8.0, 14.0};
264572c43daSJames Feist     for (auto& reading : lastReadings)
265572c43daSJames Feist     {
266572c43daSJames Feist         p->process();
267572c43daSJames Feist         EXPECT_EQ(p->getLastInput(), reading);
268572c43daSJames Feist     }
269572c43daSJames Feist }
270a076487aSPatrick Venture 
271a076487aSPatrick Venture } // namespace
272a076487aSPatrick Venture } // namespace pid_control
273