xref: /openbmc/phosphor-pid-control/test/pid_json_unittest.cpp (revision f8b6e55147148c3cfb42327ff267197a460b411c)
1 #include "conf.hpp"
2 #include "pid/buildjson.hpp"
3 
4 #include <sys/types.h>
5 
6 #include <cstdint>
7 #include <map>
8 #include <tuple>
9 
10 #include <gtest/gtest.h>
11 
12 namespace pid_control
13 {
14 namespace
15 {
16 
TEST(ZoneFromJson,emptyZone)17 TEST(ZoneFromJson, emptyZone)
18 {
19     // There is a zone key, but it's empty.
20     // This is technically invalid.
21 
22     std::map<int64_t, conf::PIDConf> pidConfig;
23     std::map<int64_t, conf::ZoneConfig> zoneConfig;
24 
25     auto j2 = R"(
26       {
27         "zones": []
28       }
29     )"_json;
30 
31     std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
32 
33     EXPECT_TRUE(pidConfig.empty());
34     EXPECT_TRUE(zoneConfig.empty());
35 }
36 
TEST(ZoneFromJson,oneZoneOnePid)37 TEST(ZoneFromJson, oneZoneOnePid)
38 {
39     // Parse a valid configuration with one zone and one PID.
40     // Intentionally omits "derivativeCoeff" to test that it is optional.
41 
42     std::map<int64_t, conf::PIDConf> pidConfig;
43     std::map<int64_t, conf::ZoneConfig> zoneConfig;
44 
45     auto j2 = R"(
46       {
47         "zones" : [{
48           "id": 1,
49           "minThermalOutput": 3000.0,
50           "failsafePercent": 75.0,
51           "pids": [{
52             "name": "fan1-5",
53             "type": "fan",
54             "inputs": ["fan1", "fan5"],
55             "setpoint": 90.0,
56             "pid": {
57               "samplePeriod": 0.1,
58               "proportionalCoeff": 0.0,
59               "integralCoeff": 0.0,
60               "feedFwdOffsetCoeff": 0.0,
61               "feedFwdGainCoeff": 0.010,
62               "integralLimit_min": 0.0,
63               "integralLimit_max": 0.0,
64               "outLim_min": 30.0,
65               "outLim_max": 100.0,
66               "slewNeg": 0.0,
67               "slewPos": 0.0
68             }
69           }]
70         }]
71       }
72     )"_json;
73 
74     std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
75     EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
76     EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
77 
78     EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan");
79     EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
80 }
81 
TEST(ZoneFromJson,marginZone)82 TEST(ZoneFromJson, marginZone)
83 {
84     // Parse a valid configuration with one zone and one PID.
85     // This is a margin zone, and has both kinds of temperature
86     // sensors in it, absolute temperature and margin temperature.
87     // Tests that TempToMargin is parsed correctly.
88 
89     std::map<int64_t, conf::PIDConf> pidConfig;
90     std::map<int64_t, conf::ZoneConfig> zoneConfig;
91 
92     auto j2 = R"(
93       {
94         "zones" : [{
95           "id": 1,
96           "minThermalOutput": 3000.0,
97           "failsafePercent": 75.0,
98           "pids": [{
99             "name": "myPid",
100             "type": "margin",
101             "inputs": ["absolute0", "absolute1", "margin0", "margin1"],
102             "tempToMargin": [
103               85.0,
104               100.0
105             ],
106             "setpoint": 10.0,
107             "pid": {
108               "samplePeriod": 0.1,
109               "proportionalCoeff": 0.0,
110               "integralCoeff": 0.0,
111               "feedFwdOffsetCoeff": 0.0,
112               "feedFwdGainCoeff": 0.010,
113               "integralLimit_min": 0.0,
114               "integralLimit_max": 0.0,
115               "outLim_min": 30.0,
116               "outLim_max": 100.0,
117               "slewNeg": 0.0,
118               "slewPos": 0.0
119             }
120           }]
121         }]
122       }
123     )"_json;
124 
125     std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
126     EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
127     EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
128 
129     EXPECT_EQ(pidConfig[1]["myPid"].type, "margin");
130     EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
131 
132     EXPECT_EQ(pidConfig[1]["myPid"].inputs[0].name, "absolute0");
133     EXPECT_DOUBLE_EQ(pidConfig[1]["myPid"].inputs[0].convertMarginZero, 85.0);
134     EXPECT_EQ(pidConfig[1]["myPid"].inputs[0].convertTempToMargin, true);
135 
136     EXPECT_EQ(pidConfig[1]["myPid"].inputs[1].name, "absolute1");
137     EXPECT_DOUBLE_EQ(pidConfig[1]["myPid"].inputs[1].convertMarginZero, 100.0);
138     EXPECT_EQ(pidConfig[1]["myPid"].inputs[1].convertTempToMargin, true);
139 
140     EXPECT_EQ(pidConfig[1]["myPid"].inputs[2].name, "margin0");
141     EXPECT_EQ(pidConfig[1]["myPid"].inputs[2].convertTempToMargin, false);
142 
143     EXPECT_EQ(pidConfig[1]["myPid"].inputs[3].name, "margin1");
144     EXPECT_EQ(pidConfig[1]["myPid"].inputs[3].convertTempToMargin, false);
145 }
146 
TEST(ZoneFromJson,oneZoneOnePidWithHysteresis)147 TEST(ZoneFromJson, oneZoneOnePidWithHysteresis)
148 {
149     // Parse a valid configuration with one zone and one PID and the PID uses
150     // Hysteresis parameters.
151 
152     std::map<int64_t, conf::PIDConf> pidConfig;
153     std::map<int64_t, conf::ZoneConfig> zoneConfig;
154 
155     auto j2 = R"(
156       {
157         "zones" : [{
158           "id": 1,
159           "minThermalOutput": 3000.0,
160           "failsafePercent": 75.0,
161           "pids": [{
162             "name": "fan1-5",
163             "type": "fan",
164             "inputs": ["fan1", "fan5"],
165             "setpoint": 90.0,
166             "pid": {
167               "samplePeriod": 0.1,
168               "proportionalCoeff": 0.0,
169               "integralCoeff": 0.0,
170               "derivativeCoeff": 0.0,
171               "feedFwdOffsetCoeff": 0.0,
172               "feedFwdGainCoeff": 0.010,
173               "integralLimit_min": 0.0,
174               "integralLimit_max": 0.0,
175               "outLim_min": 30.0,
176               "outLim_max": 100.0,
177               "slewNeg": 0.0,
178               "slewPos": 0.0,
179               "positiveHysteresis": 1000.0,
180               "negativeHysteresis": 9000.0
181             }
182           }]
183         }]
184       }
185     )"_json;
186 
187     std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
188     EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
189     EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
190 
191     EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan");
192     EXPECT_DOUBLE_EQ(pidConfig[1]["fan1-5"].pidInfo.positiveHysteresis, 1000.0);
193 
194     EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
195 }
196 
TEST(ZoneFromJson,oneZoneOneStepwiseWithHysteresis)197 TEST(ZoneFromJson, oneZoneOneStepwiseWithHysteresis)
198 {
199     // Parse a valid configuration with one zone and one PID and the PID uses
200     // Hysteresis parameters.
201 
202     std::map<int64_t, conf::PIDConf> pidConfig;
203     std::map<int64_t, conf::ZoneConfig> zoneConfig;
204 
205     auto j2 = R"(
206       {
207         "zones" : [{
208           "id": 1,
209           "minThermalOutput": 3000.0,
210           "failsafePercent": 75.0,
211           "pids": [{
212             "name": "temp1",
213             "type": "stepwise",
214             "inputs": ["temp1"],
215             "setpoint": 30.0,
216             "pid": {
217               "samplePeriod": 0.1,
218               "positiveHysteresis": 1.0,
219               "negativeHysteresis": 1.0,
220               "isCeiling": false,
221               "reading": {
222                 "0": 45,
223                 "1": 46,
224                 "2": 47,
225                 "3": 48,
226                 "4": 49,
227                 "5": 50,
228                 "6": 51,
229                 "7": 52,
230                 "8": 53,
231                 "9": 54,
232                 "10": 55,
233                 "11": 56,
234                 "12": 57,
235                 "13": 58,
236                 "14": 59,
237                 "15": 60,
238                 "16": 61,
239                 "17": 62,
240                 "18": 63,
241                 "19": 64
242               },
243               "output": {
244                 "0": 5000,
245                 "1": 2400,
246                 "2": 2600,
247                 "3": 2800,
248                 "4": 3000,
249                 "5": 3200,
250                 "6": 3400,
251                 "7": 3600,
252                 "8": 3800,
253                 "9": 4000,
254                 "10": 4200,
255                 "11": 4400,
256                 "12": 4600,
257                 "13": 4800,
258                 "14": 5000,
259                 "15": 5200,
260                 "16": 5400,
261                 "17": 5600,
262                 "18": 5800,
263                 "19": 6000
264               }
265             }
266           }]
267         }]
268       }
269     )"_json;
270 
271     std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
272     EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
273     EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
274 
275     EXPECT_EQ(pidConfig[1]["temp1"].type, "stepwise");
276     EXPECT_DOUBLE_EQ(pidConfig[1]["temp1"].stepwiseInfo.positiveHysteresis,
277                      1.0);
278 
279     EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
280 }
281 
TEST(ZoneFromJson,getCycleInterval)282 TEST(ZoneFromJson, getCycleInterval)
283 {
284     // Parse a valid configuration with one zone and one PID and the zone have
285     // cycleIntervalTime and updateThermalsTime parameters.
286 
287     std::map<int64_t, conf::PIDConf> pidConfig;
288     std::map<int64_t, conf::ZoneConfig> zoneConfig;
289 
290     auto j2 = R"(
291       {
292         "zones" : [{
293           "id": 1,
294           "minThermalOutput": 3000.0,
295           "failsafePercent": 75.0,
296           "cycleIntervalTimeMS": 1000.0,
297           "updateThermalsTimeMS": 1000.0,
298           "pids": [{
299             "name": "fan1-5",
300             "type": "fan",
301             "inputs": ["fan1", "fan5"],
302             "setpoint": 90.0,
303             "pid": {
304               "samplePeriod": 0.1,
305               "proportionalCoeff": 0.0,
306               "integralCoeff": 0.0,
307               "derivativeCoeff": 0.0,
308               "feedFwdOffsetCoeff": 0.0,
309               "feedFwdGainCoeff": 0.010,
310               "integralLimit_min": 0.0,
311               "integralLimit_max": 0.0,
312               "outLim_min": 30.0,
313               "outLim_max": 100.0,
314               "slewNeg": 0.0,
315               "slewPos": 0.0
316             }
317           }]
318         }]
319       }
320     )"_json;
321 
322     std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
323     EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
324     EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
325 
326     EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan");
327     EXPECT_EQ(zoneConfig[1].cycleTime.cycleIntervalTimeMS,
328               static_cast<u_int64_t>(1000));
329     EXPECT_EQ(zoneConfig[1].cycleTime.updateThermalsTimeMS,
330               static_cast<u_int64_t>(1000));
331     EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
332 }
333 
334 } // namespace
335 } // namespace pid_control
336