blob: 57932c94e1384d368fabe3bb68db500596ecd3f7 [file] [log] [blame]
Patrick Venture566a1512018-06-12 14:51:07 -07001#include "pid/ec/pid.hpp"
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07002#include "pid/fancontroller.hpp"
Patrick Venture566a1512018-06-12 14:51:07 -07003#include "test/sensor_mock.hpp"
4#include "test/zone_mock.hpp"
5
Patrick Ventureda4a5dd2018-08-31 09:42:48 -07006#include <string>
7#include <vector>
8
9#include <gmock/gmock.h>
10#include <gtest/gtest.h>
11
12using ::testing::_;
Patrick Venture566a1512018-06-12 14:51:07 -070013using ::testing::DoubleEq;
14using ::testing::Invoke;
15using ::testing::Return;
16using ::testing::StrEq;
Patrick Venture566a1512018-06-12 14:51:07 -070017
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070018TEST(FanControllerTest, BoringFactoryTest)
19{
Patrick Venture566a1512018-06-12 14:51:07 -070020 // Verify the factory will properly build the FanPIDController in the
21 // boring (uninteresting) case.
22 ZoneMock z;
23
24 std::vector<std::string> inputs = {"fan0"};
25 ec::pidinfo initial;
26
27 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -070028 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -070029 // Success
30 EXPECT_FALSE(p == nullptr);
31}
32
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070033TEST(FanControllerTest, VerifyFactoryFailsWithZeroInputs)
34{
Patrick Venture566a1512018-06-12 14:51:07 -070035 // A fan controller needs at least one input.
36
37 ZoneMock z;
38
39 std::vector<std::string> inputs = {};
40 ec::pidinfo initial;
41
42 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -070043 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -070044 EXPECT_TRUE(p == nullptr);
45}
46
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070047TEST(FanControllerTest, InputProc_AllSensorsReturnZero)
48{
Patrick Venture566a1512018-06-12 14:51:07 -070049 // If all your inputs are 0, return 0.
50
51 ZoneMock z;
52
53 std::vector<std::string> inputs = {"fan0", "fan1"};
54 ec::pidinfo initial;
55
56 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -070057 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -070058 EXPECT_FALSE(p == nullptr);
59
60 EXPECT_CALL(z, getCachedValue(StrEq("fan0"))).WillOnce(Return(0));
61 EXPECT_CALL(z, getCachedValue(StrEq("fan1"))).WillOnce(Return(0));
62
Patrick Venture563a3562018-10-30 09:31:26 -070063 EXPECT_EQ(0.0, p->inputProc());
Patrick Venture566a1512018-06-12 14:51:07 -070064}
65
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070066TEST(FanControllerTest, InputProc_IfSensorNegativeIsIgnored)
67{
Patrick Venture566a1512018-06-12 14:51:07 -070068 // A sensor value returning sub-zero is ignored as an error.
69 ZoneMock z;
70
71 std::vector<std::string> inputs = {"fan0", "fan1"};
72 ec::pidinfo initial;
73
74 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -070075 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -070076 EXPECT_FALSE(p == nullptr);
77
78 EXPECT_CALL(z, getCachedValue(StrEq("fan0"))).WillOnce(Return(-1));
79 EXPECT_CALL(z, getCachedValue(StrEq("fan1"))).WillOnce(Return(-1));
80
Patrick Venture563a3562018-10-30 09:31:26 -070081 EXPECT_EQ(0.0, p->inputProc());
Patrick Venture566a1512018-06-12 14:51:07 -070082}
83
Patrick Ventureda4a5dd2018-08-31 09:42:48 -070084TEST(FanControllerTest, InputProc_ChoosesMinimumValue)
85{
Patrick Venture566a1512018-06-12 14:51:07 -070086 // Verify it selects the minimum value from its inputs.
87
88 ZoneMock z;
89
90 std::vector<std::string> inputs = {"fan0", "fan1", "fan2"};
91 ec::pidinfo initial;
92
93 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -070094 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -070095 EXPECT_FALSE(p == nullptr);
96
97 EXPECT_CALL(z, getCachedValue(StrEq("fan0"))).WillOnce(Return(10.0));
98 EXPECT_CALL(z, getCachedValue(StrEq("fan1"))).WillOnce(Return(30.0));
99 EXPECT_CALL(z, getCachedValue(StrEq("fan2"))).WillOnce(Return(5.0));
100
Patrick Venture563a3562018-10-30 09:31:26 -0700101 EXPECT_EQ(5.0, p->inputProc());
Patrick Venture566a1512018-06-12 14:51:07 -0700102}
103
104// The direction is unused presently, but these tests validate the logic.
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700105TEST(FanControllerTest, SetPtProc_SpeedChanges_VerifyDirection)
106{
Patrick Venture566a1512018-06-12 14:51:07 -0700107 // The fan direction defaults to neutral, because we have no data. Verify
108 // that after this point it appropriately will indicate speeding up or
109 // slowing down based on the RPM values specified.
110
111 ZoneMock z;
112
113 std::vector<std::string> inputs = {"fan0", "fan1"};
114 ec::pidinfo initial;
115
116 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -0700117 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -0700118 EXPECT_FALSE(p == nullptr);
119 // Grab pointer for mocking.
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700120 FanController* fp = reinterpret_cast<FanController*>(p.get());
Patrick Venture566a1512018-06-12 14:51:07 -0700121
122 // Fanspeed starts are Neutral.
123 EXPECT_EQ(FanSpeedDirection::NEUTRAL, fp->getFanDirection());
124
125 // getMaxRPMRequest returns a higher value than 0, so the fans should be
126 // marked as speeding up.
127 EXPECT_CALL(z, getMaxRPMRequest()).WillOnce(Return(10.0));
Patrick Venture563a3562018-10-30 09:31:26 -0700128 EXPECT_EQ(10.0, p->setptProc());
Patrick Venture566a1512018-06-12 14:51:07 -0700129 EXPECT_EQ(FanSpeedDirection::UP, fp->getFanDirection());
130
131 // getMaxRPMRequest returns a lower value than 10, so the fans should be
132 // marked as slowing down.
133 EXPECT_CALL(z, getMaxRPMRequest()).WillOnce(Return(5.0));
Patrick Venture563a3562018-10-30 09:31:26 -0700134 EXPECT_EQ(5.0, p->setptProc());
Patrick Venture566a1512018-06-12 14:51:07 -0700135 EXPECT_EQ(FanSpeedDirection::DOWN, fp->getFanDirection());
136
137 // getMaxRPMRequest returns the same value, so the fans should be marked as
138 // neutral.
139 EXPECT_CALL(z, getMaxRPMRequest()).WillOnce(Return(5.0));
Patrick Venture563a3562018-10-30 09:31:26 -0700140 EXPECT_EQ(5.0, p->setptProc());
Patrick Venture566a1512018-06-12 14:51:07 -0700141 EXPECT_EQ(FanSpeedDirection::NEUTRAL, fp->getFanDirection());
142}
143
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700144TEST(FanControllerTest, OutputProc_VerifiesIfFailsafeEnabledInputIsIgnored)
145{
Patrick Venture566a1512018-06-12 14:51:07 -0700146 // Verify that if failsafe mode is enabled and the input value for the fans
147 // is below the failsafe minimum value, the input is not used and the fans
148 // are driven at failsafe RPM.
149
150 ZoneMock z;
151
152 std::vector<std::string> inputs = {"fan0", "fan1"};
153 ec::pidinfo initial;
154
155 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -0700156 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -0700157 EXPECT_FALSE(p == nullptr);
158
159 EXPECT_CALL(z, getFailSafeMode()).WillOnce(Return(true));
160 EXPECT_CALL(z, getFailSafePercent()).Times(2).WillRepeatedly(Return(75.0));
161
162 int64_t timeout = 0;
163 std::unique_ptr<Sensor> s1 = std::make_unique<SensorMock>("fan0", timeout);
164 std::unique_ptr<Sensor> s2 = std::make_unique<SensorMock>("fan1", timeout);
165 // Grab pointers for mocking.
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700166 SensorMock* sm1 = reinterpret_cast<SensorMock*>(s1.get());
167 SensorMock* sm2 = reinterpret_cast<SensorMock*>(s2.get());
Patrick Venture566a1512018-06-12 14:51:07 -0700168
169 EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
170 EXPECT_CALL(*sm1, write(0.75));
171 EXPECT_CALL(z, getSensor(StrEq("fan1"))).WillOnce(Return(s2.get()));
172 EXPECT_CALL(*sm2, write(0.75));
173
Patrick Venture563a3562018-10-30 09:31:26 -0700174 // This is a fan PID, so calling outputProc will try to write this value
Patrick Venture566a1512018-06-12 14:51:07 -0700175 // to the sensors.
176
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700177 // Setting 50%, will end up being 75% because the sensors are in failsafe
178 // mode.
Patrick Venture563a3562018-10-30 09:31:26 -0700179 p->outputProc(50.0);
Patrick Venture566a1512018-06-12 14:51:07 -0700180}
181
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700182TEST(FanControllerTest, OutputProc_BehavesAsExpected)
183{
Patrick Venture566a1512018-06-12 14:51:07 -0700184 // Verifies that when the system is not in failsafe mode, the input value
Patrick Venture563a3562018-10-30 09:31:26 -0700185 // to outputProc is used to drive the sensors (fans).
Patrick Venture566a1512018-06-12 14:51:07 -0700186
187 ZoneMock z;
188
189 std::vector<std::string> inputs = {"fan0", "fan1"};
190 ec::pidinfo initial;
191
192 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -0700193 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -0700194 EXPECT_FALSE(p == nullptr);
195
196 EXPECT_CALL(z, getFailSafeMode()).WillOnce(Return(false));
197
198 int64_t timeout = 0;
199 std::unique_ptr<Sensor> s1 = std::make_unique<SensorMock>("fan0", timeout);
200 std::unique_ptr<Sensor> s2 = std::make_unique<SensorMock>("fan1", timeout);
201 // Grab pointers for mocking.
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700202 SensorMock* sm1 = reinterpret_cast<SensorMock*>(s1.get());
203 SensorMock* sm2 = reinterpret_cast<SensorMock*>(s2.get());
Patrick Venture566a1512018-06-12 14:51:07 -0700204
205 EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
206 EXPECT_CALL(*sm1, write(0.5));
207 EXPECT_CALL(z, getSensor(StrEq("fan1"))).WillOnce(Return(s2.get()));
208 EXPECT_CALL(*sm2, write(0.5));
209
Patrick Venture563a3562018-10-30 09:31:26 -0700210 // This is a fan PID, so calling outputProc will try to write this value
Patrick Venture566a1512018-06-12 14:51:07 -0700211 // to the sensors.
Patrick Venture563a3562018-10-30 09:31:26 -0700212 p->outputProc(50.0);
Patrick Venture566a1512018-06-12 14:51:07 -0700213}
214
Patrick Ventureda4a5dd2018-08-31 09:42:48 -0700215TEST(FanControllerTest, OutputProc_VerifyFailSafeIgnoredIfInputHigher)
216{
Patrick Venture566a1512018-06-12 14:51:07 -0700217 // If the requested output is higher than the failsafe value, then use the
Patrick Venture563a3562018-10-30 09:31:26 -0700218 // value provided to outputProc.
Patrick Venture566a1512018-06-12 14:51:07 -0700219
220 ZoneMock z;
221
222 std::vector<std::string> inputs = {"fan0"};
223 ec::pidinfo initial;
224
225 std::unique_ptr<PIDController> p =
Patrick Venture563a3562018-10-30 09:31:26 -0700226 FanController::createFanPid(&z, "fan1", inputs, initial);
Patrick Venture566a1512018-06-12 14:51:07 -0700227 EXPECT_FALSE(p == nullptr);
228
229 EXPECT_CALL(z, getFailSafeMode()).WillOnce(Return(true));
230 EXPECT_CALL(z, getFailSafePercent()).WillOnce(Return(75.0));
231
232 int64_t timeout = 0;
233 std::unique_ptr<Sensor> s1 = std::make_unique<SensorMock>("fan0", timeout);
234 // Grab pointer for mocking.
Patrick Venturee2ec0f62018-09-04 12:30:27 -0700235 SensorMock* sm1 = reinterpret_cast<SensorMock*>(s1.get());
Patrick Venture566a1512018-06-12 14:51:07 -0700236
237 // Converting from float to double for expectation.
238 float percent = 80;
239 double value = static_cast<double>(percent / 100);
240
241 EXPECT_CALL(z, getSensor(StrEq("fan0"))).WillOnce(Return(s1.get()));
242 EXPECT_CALL(*sm1, write(value));
243
Patrick Venture563a3562018-10-30 09:31:26 -0700244 // This is a fan PID, so calling outputProc will try to write this value
Patrick Venture566a1512018-06-12 14:51:07 -0700245 // to the sensors.
Patrick Venture563a3562018-10-30 09:31:26 -0700246 p->outputProc(percent);
Patrick Venture566a1512018-06-12 14:51:07 -0700247}