xref: /openbmc/phosphor-power/phosphor-regulators/test/validate-regulators-config_tests.cpp (revision 3728f56287b55d2745d14e278728d3feffde977e)
1 /**
2  * Copyright c 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/wait.h>
20 
21 #include <nlohmann/json.hpp>
22 
23 #include <fstream>
24 
25 #include <gtest/gtest.h>
26 
27 #define EXPECT_FILE_VALID(configFile) expectFileValid(configFile)
28 #define EXPECT_FILE_INVALID(configFile, expectedErrorMessage,                  \
29                             expectedOutputMessage)                             \
30     expectFileInvalid(configFile, expectedErrorMessage, expectedOutputMessage)
31 #define EXPECT_JSON_VALID(configFileJson) expectJsonValid(configFileJson)
32 #define EXPECT_JSON_INVALID(configFileJson, expectedErrorMessage,              \
33                             expectedOutputMessage)                             \
34     expectJsonInvalid(configFileJson, expectedErrorMessage,                    \
35                       expectedOutputMessage)
36 
37 using json = nlohmann::json;
38 
39 const json validConfigFile = R"(
40     {
41       "comments": [ "Config file for a FooBar one-chassis system" ],
42 
43       "rules": [
44         {
45           "comments": [ "Sets output voltage for a PMBus regulator rail" ],
46           "id": "set_voltage_rule",
47           "actions": [
48             {
49               "pmbus_write_vout_command": {
50                 "format": "linear"
51               }
52             }
53           ]
54         }
55       ],
56 
57       "chassis": [
58         {
59           "comments": [ "Chassis number 1 containing CPUs and memory" ],
60           "number": 1,
61           "devices": [
62             {
63               "comments": [ "IR35221 regulator producing the Vdd rail" ],
64               "id": "vdd_regulator",
65               "is_regulator": true,
66               "fru": "/system/chassis/motherboard/regulator1",
67               "i2c_interface": {
68                 "bus": 1,
69                 "address": "0x70"
70               },
71               "rails": [
72                 {
73                   "comments": [ "Vdd rail" ],
74                   "id": "vdd",
75                   "configuration": {
76                     "volts": 1.03,
77                     "rule_id": "set_voltage_rule"
78                   },
79                   "sensor_monitoring": {
80                     "rule_id": "read_sensors_rule"
81                   }
82                 }
83               ]
84             }
85           ]
86         }
87       ]
88     }
89 )"_json;
90 
91 std::string createTmpFile()
92 {
93     // create temporary file using mkstemp under /tmp/. random name for XXXXXX
94     char fileName[] = "/tmp/temp-XXXXXX";
95     int fd = mkstemp(fileName);
96     if (fd == -1)
97     {
98         perror("Can't create temporary file");
99     }
100     close(fd);
101     return fileName;
102 }
103 
104 std::string getValidationToolCommand(const std::string& configFileName)
105 {
106     std::string command = "python ../tools/validate-regulators-config.py -s \
107                            ../schema/config_schema.json -c ";
108     command += configFileName;
109     return command;
110 }
111 
112 int runToolForOutput(const std::string& configFileName, std::string& output,
113                      bool isReadingStderr = false)
114 {
115     // run the validation tool with the temporary file and return the output
116     // of the validation tool.
117     std::string command = getValidationToolCommand(configFileName);
118     // reading the stderr while isReadingStderr is true.
119     if (isReadingStderr == true)
120     {
121         command += " 2>&1 >/dev/null";
122     }
123     // get the jsonschema print from validation tool.
124     char buffer[256];
125     std::string result = "";
126     // to get the stdout from the validation tool.
127     FILE* pipe = popen(command.c_str(), "r");
128     if (!pipe)
129     {
130         throw std::runtime_error("popen() failed!");
131     }
132     while (!std::feof(pipe))
133     {
134         if (fgets(buffer, sizeof buffer, pipe) != NULL)
135         {
136             result += buffer;
137         }
138     }
139     int returnValue = pclose(pipe);
140     // Check if pclose() failed
141     if (returnValue == -1)
142     {
143         // unable to close pipe.  Print error and exit function.
144         throw std::runtime_error("pclose() failed!");
145     }
146     std::string firstLine = result.substr(0, result.find('\n'));
147     output = firstLine;
148     // Get command exit status from return value
149     int exitStatus = WEXITSTATUS(returnValue);
150     return exitStatus;
151 }
152 
153 void expectFileValid(const std::string& configFileName)
154 {
155     std::string errorMessage = "";
156     std::string outputMessage = "";
157     EXPECT_EQ(runToolForOutput(configFileName, errorMessage, true), 0);
158     EXPECT_EQ(runToolForOutput(configFileName, outputMessage), 0);
159     EXPECT_EQ(errorMessage, "");
160     EXPECT_EQ(outputMessage, "");
161 }
162 
163 void expectFileInvalid(const std::string& configFileName,
164                        const std::string& expectedErrorMessage,
165                        const std::string& expectedOutputMessage)
166 {
167     std::string errorMessage = "";
168     std::string outputMessage = "";
169     EXPECT_EQ(runToolForOutput(configFileName, errorMessage, true), 1);
170     EXPECT_EQ(runToolForOutput(configFileName, outputMessage), 1);
171     EXPECT_EQ(errorMessage, expectedErrorMessage);
172     EXPECT_EQ(outputMessage, expectedOutputMessage);
173 }
174 
175 void expectJsonValid(const json configFileJson)
176 {
177     std::string fileName;
178     fileName = createTmpFile();
179     std::string jsonData = configFileJson.dump();
180     std::ofstream out(fileName);
181     out << jsonData;
182     out.close();
183 
184     EXPECT_FILE_VALID(fileName);
185     unlink(fileName.c_str());
186 }
187 
188 void expectJsonInvalid(const json configFileJson,
189                        const std::string& expectedErrorMessage,
190                        const std::string& expectedOutputMessage)
191 {
192     std::string fileName;
193     fileName = createTmpFile();
194     std::string jsonData = configFileJson.dump();
195     std::ofstream out(fileName);
196     out << jsonData;
197     out.close();
198 
199     EXPECT_FILE_INVALID(fileName, expectedErrorMessage, expectedOutputMessage);
200     unlink(fileName.c_str());
201 }
202 
203 TEST(ValidateRegulatorsConfigTest, Rule)
204 {
205     // valid test comments property, id property,
206     // action property specified.
207     {
208         json configFile = validConfigFile;
209         EXPECT_JSON_VALID(configFile);
210     }
211 
212     // valid test rule with no comments
213     {
214         json configFile = validConfigFile;
215         configFile["rules"][0].erase("comments");
216         EXPECT_JSON_VALID(configFile);
217     }
218 
219     // invalid test comments property has invalid value type
220     {
221         json configFile = validConfigFile;
222         configFile["rules"][0]["comments"] = {1};
223         EXPECT_JSON_INVALID(configFile, "Validation failed.",
224                             "1 is not of type u'string'");
225     }
226 
227     // invalid test rule with no ID
228     {
229         json configFile = validConfigFile;
230         configFile["rules"][0].erase("id");
231         EXPECT_JSON_INVALID(configFile, "Validation failed.",
232                             "u'id' is a required property");
233     }
234 
235     // invalid test id property has invalid value type (not string)
236     {
237         json configFile = validConfigFile;
238         configFile["rules"][0]["id"] = true;
239         EXPECT_JSON_INVALID(configFile, "Validation failed.",
240                             "True is not of type u'string'");
241     }
242 
243     // invalid test id property has invalid value
244     {
245         json configFile = validConfigFile;
246         configFile["rules"][0]["id"] = "foo%";
247         EXPECT_JSON_INVALID(configFile, "Validation failed.",
248                             "u'foo%' does not match u'^[A-Za-z0-9_]+$'");
249     }
250 
251     // invalid test rule with no actions property
252     {
253         json configFile = validConfigFile;
254         configFile["rules"][0].erase("actions");
255         EXPECT_JSON_INVALID(configFile, "Validation failed.",
256                             "u'actions' is a required property");
257     }
258 
259     // valid test rule with multiple actions
260     {
261         json configFile = validConfigFile;
262         configFile["rules"][0]["actions"][1]["run_rule"] =
263             "set_page0_voltage_rule";
264         EXPECT_JSON_VALID(configFile);
265     }
266 
267     // invalid test actions property has invalid value type (not an array)
268     {
269         json configFile = validConfigFile;
270         configFile["rules"][0]["actions"] = 1;
271         EXPECT_JSON_INVALID(configFile, "Validation failed.",
272                             "1 is not of type u'array'");
273     }
274 
275     // invalid test actions property has invalid value of action
276     {
277         json configFile = validConfigFile;
278         configFile["rules"][0]["actions"][0] = "foo";
279         EXPECT_JSON_INVALID(configFile, "Validation failed.",
280                             "u'foo' is not of type u'object'");
281     }
282 
283     // invalid test actions property has empty array
284     {
285         json configFile = validConfigFile;
286         configFile["rules"][0]["actions"] = json::array();
287         EXPECT_JSON_INVALID(configFile, "Validation failed.",
288                             "[] is too short");
289     }
290 }
291 TEST(ValidateRegulatorsConfigTest, And)
292 {
293     // Valid.
294     {
295         json configFile = validConfigFile;
296         json andAction =
297             R"(
298                 {
299                  "and": [
300                     { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
301                     { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
302                   ]
303                 }
304             )"_json;
305         configFile["rules"][0]["actions"].push_back(andAction);
306         EXPECT_JSON_VALID(configFile);
307     }
308 
309     // Invalid: actions property value is an empty array.
310     {
311         json configFile = validConfigFile;
312         json andAction =
313             R"(
314                 {
315                  "and": []
316                 }
317             )"_json;
318         configFile["rules"][0]["actions"].push_back(andAction);
319         EXPECT_JSON_INVALID(configFile, "Validation failed.",
320                             "[] is too short");
321     }
322 
323     // Invalid: actions property has incorrect value data type.
324     {
325         json configFile = validConfigFile;
326         json andAction =
327             R"(
328                 {
329                  "and": true
330                 }
331             )"_json;
332         configFile["rules"][0]["actions"].push_back(andAction);
333         EXPECT_JSON_INVALID(configFile, "Validation failed.",
334                             "True is not of type u'array'");
335     }
336 
337     // Invalid: actions property value contains wrong element type
338     {
339         json configFile = validConfigFile;
340         json andAction =
341             R"(
342                 {
343                  "and": ["foo"]
344                 }
345             )"_json;
346         configFile["rules"][0]["actions"].push_back(andAction);
347         EXPECT_JSON_INVALID(configFile, "Validation failed.",
348                             "u'foo' is not of type u'object'");
349     }
350 }
351 TEST(ValidateRegulatorsConfigTest, Chassis)
352 {
353     // Valid: test chassis.
354     {
355         json configFile = validConfigFile;
356         EXPECT_JSON_VALID(configFile);
357     }
358     // Valid: test chassis with required properties.
359     {
360         json configFile = validConfigFile;
361         configFile["chassis"][0].erase("comments");
362         configFile["chassis"][0].erase("devices");
363         EXPECT_JSON_VALID(configFile);
364     }
365     // Invalid: test chassis with no number.
366     {
367         json configFile = validConfigFile;
368         configFile["chassis"][0].erase("number");
369         EXPECT_JSON_INVALID(configFile, "Validation failed.",
370                             "u'number' is a required property");
371     }
372     // Invalid: test chassis with property comments wrong type.
373     {
374         json configFile = validConfigFile;
375         configFile["chassis"][0]["comments"] = true;
376         EXPECT_JSON_INVALID(configFile, "Validation failed.",
377                             "True is not of type u'array'");
378     }
379     // Invalid: test chassis with property number wrong type.
380     {
381         json configFile = validConfigFile;
382         configFile["chassis"][0]["number"] = 1.3;
383         EXPECT_JSON_INVALID(configFile, "Validation failed.",
384                             "1.3 is not of type u'integer'");
385     }
386     // Invalid: test chassis with property devices wrong type.
387     {
388         json configFile = validConfigFile;
389         configFile["chassis"][0]["devices"] = true;
390         EXPECT_JSON_INVALID(configFile, "Validation failed.",
391                             "True is not of type u'array'");
392     }
393     // Invalid: test chassis with property comments empty array.
394     {
395         json configFile = validConfigFile;
396         configFile["chassis"][0]["comments"] = json::array();
397         EXPECT_JSON_INVALID(configFile, "Validation failed.",
398                             "[] is too short");
399     }
400     // Invalid: test chassis with property devices empty array.
401     {
402         json configFile = validConfigFile;
403         configFile["chassis"][0]["devices"] = json::array();
404         EXPECT_JSON_INVALID(configFile, "Validation failed.",
405                             "[] is too short");
406     }
407     // Invalid: test chassis with property number less than 1.
408     {
409         json configFile = validConfigFile;
410         configFile["chassis"][0]["number"] = 0;
411         EXPECT_JSON_INVALID(configFile, "Validation failed.",
412                             "0 is less than the minimum of 1");
413     }
414 }
415 TEST(ValidateRegulatorsConfigTest, ComparePresence)
416 {
417     json comparePresenceFile = validConfigFile;
418     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
419         "/system/chassis/motherboard/regulator2";
420     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
421         true;
422     // Valid.
423     {
424         json configFile = comparePresenceFile;
425         EXPECT_JSON_VALID(configFile);
426     }
427 
428     // Invalid: no FRU property.
429     {
430         json configFile = comparePresenceFile;
431         configFile["rules"][0]["actions"][1]["compare_presence"].erase("fru");
432         EXPECT_JSON_INVALID(configFile, "Validation failed.",
433                             "u'fru' is a required property");
434     }
435 
436     // Invalid: FRU property length is string less than 1.
437     {
438         json configFile = comparePresenceFile;
439         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = "";
440         EXPECT_JSON_INVALID(configFile, "Validation failed.",
441                             "u'' is too short");
442     }
443 
444     // Invalid: no value property.
445     {
446         json configFile = comparePresenceFile;
447         configFile["rules"][0]["actions"][1]["compare_presence"].erase("value");
448         EXPECT_JSON_INVALID(configFile, "Validation failed.",
449                             "u'value' is a required property");
450     }
451 
452     // Invalid: value property type is not boolean.
453     {
454         json configFile = comparePresenceFile;
455         configFile["rules"][0]["actions"][1]["compare_presence"]["value"] = "1";
456         EXPECT_JSON_INVALID(configFile, "Validation failed.",
457                             "u'1' is not of type u'boolean'");
458     }
459 
460     // Invalid: FRU property type is not string.
461     {
462         json configFile = comparePresenceFile;
463         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = 1;
464         EXPECT_JSON_INVALID(configFile, "Validation failed.",
465                             "1 is not of type u'string'");
466     }
467 }
468 TEST(ValidateRegulatorsConfigTest, CompareVpd)
469 {
470     json compareVpdFile = validConfigFile;
471     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
472         "/system/chassis/motherboard/regulator2";
473     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
474     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
475 
476     // Valid.
477     {
478         json configFile = compareVpdFile;
479         EXPECT_JSON_VALID(configFile);
480     }
481 
482     // Invalid: no FRU property.
483     {
484         json configFile = compareVpdFile;
485         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("fru");
486         EXPECT_JSON_INVALID(configFile, "Validation failed.",
487                             "u'fru' is a required property");
488     }
489 
490     // Invalid: no keyword property.
491     {
492         json configFile = compareVpdFile;
493         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("keyword");
494         EXPECT_JSON_INVALID(configFile, "Validation failed.",
495                             "u'keyword' is a required property");
496     }
497 
498     // Invalid: no value property.
499     {
500         json configFile = compareVpdFile;
501         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("value");
502         EXPECT_JSON_INVALID(configFile, "Validation failed.",
503                             "u'value' is a required property");
504     }
505 
506     // Invalid: property FRU wrong type.
507     {
508         json configFile = compareVpdFile;
509         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = 1;
510         EXPECT_JSON_INVALID(configFile, "Validation failed.",
511                             "1 is not of type u'string'");
512     }
513 
514     // Invalid: property FRU is string less than 1.
515     {
516         json configFile = compareVpdFile;
517         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = "";
518         EXPECT_JSON_INVALID(configFile, "Validation failed.",
519                             "u'' is too short");
520     }
521 
522     // Invalid: property keyword is not "CCIN", "Manufacturer", "Model",
523     // "PartNumber"
524     {
525         json configFile = compareVpdFile;
526         configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] =
527             "Number";
528         EXPECT_JSON_INVALID(configFile, "Validation failed.",
529                             "u'Number' is not one of [u'CCIN', "
530                             "u'Manufacturer', u'Model', u'PartNumber']");
531     }
532 
533     // Invalid: property value wrong type.
534     {
535         json configFile = compareVpdFile;
536         configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = 1;
537         EXPECT_JSON_INVALID(configFile, "Validation failed.",
538                             "1 is not of type u'string'");
539     }
540 }
541 TEST(ValidateRegulatorsConfigTest, I2CCompareBit)
542 {
543     json i2cCompareBitFile = validConfigFile;
544     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
545         "0xA0";
546     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
547         3;
548     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
549     // Valid: test rule actions i2c_compare_bit.
550     {
551         json configFile = i2cCompareBitFile;
552         EXPECT_JSON_VALID(configFile);
553     }
554     // Invalid: test i2c_compare_bit with no register.
555     {
556         json configFile = i2cCompareBitFile;
557         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
558             "register");
559         EXPECT_JSON_INVALID(configFile, "Validation failed.",
560                             "u'register' is a required property");
561     }
562     // Invalid: test i2c_compare_bit with no position.
563     {
564         json configFile = i2cCompareBitFile;
565         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
566             "position");
567         EXPECT_JSON_INVALID(configFile, "Validation failed.",
568                             "u'position' is a required property");
569     }
570     // Invalid: test i2c_compare_bit with no value.
571     {
572         json configFile = i2cCompareBitFile;
573         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase("value");
574         EXPECT_JSON_INVALID(configFile, "Validation failed.",
575                             "u'value' is a required property");
576     }
577     // Invalid: test i2c_compare_bit with register wrong type.
578     {
579         json configFile = i2cCompareBitFile;
580         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] = 1;
581         EXPECT_JSON_INVALID(configFile, "Validation failed.",
582                             "1 is not of type u'string'");
583     }
584     // Invalid: test i2c_compare_bit with register wrong format.
585     {
586         json configFile = i2cCompareBitFile;
587         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
588             "0xA00";
589         EXPECT_JSON_INVALID(configFile, "Validation failed.",
590                             "u'0xA00' does not match u'^0x[0-9A-Fa-f]{2}$'");
591     }
592     // Invalid: test i2c_compare_bit with position wrong type.
593     {
594         json configFile = i2cCompareBitFile;
595         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
596             3.1;
597         EXPECT_JSON_INVALID(configFile, "Validation failed.",
598                             "3.1 is not of type u'integer'");
599     }
600     // Invalid: test i2c_compare_bit with position greater than 7.
601     {
602         json configFile = i2cCompareBitFile;
603         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 8;
604         EXPECT_JSON_INVALID(configFile, "Validation failed.",
605                             "8 is greater than the maximum of 7");
606     }
607     // Invalid: test i2c_compare_bit with position less than 0.
608     {
609         json configFile = i2cCompareBitFile;
610         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
611             -1;
612         EXPECT_JSON_INVALID(configFile, "Validation failed.",
613                             "-1 is less than the minimum of 0");
614     }
615     // Invalid: test i2c_compare_bit with value wrong type.
616     {
617         json configFile = i2cCompareBitFile;
618         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = "1";
619         EXPECT_JSON_INVALID(configFile, "Validation failed.",
620                             "u'1' is not of type u'integer'");
621     }
622     // Invalid: test i2c_compare_bit with value greater than 1.
623     {
624         json configFile = i2cCompareBitFile;
625         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 2;
626         EXPECT_JSON_INVALID(configFile, "Validation failed.",
627                             "2 is greater than the maximum of 1");
628     }
629     // Invalid: test i2c_compare_bit with value less than 0.
630     {
631         json configFile = i2cCompareBitFile;
632         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = -1;
633         EXPECT_JSON_INVALID(configFile, "Validation failed.",
634                             "-1 is less than the minimum of 0");
635     }
636 }
637 TEST(ValidateRegulatorsConfigTest, I2CCompareByte)
638 {
639     json i2cCompareByteFile = validConfigFile;
640     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]
641                       ["register"] = "0x82";
642     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
643         "0x40";
644     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
645         "0x7F";
646     // Valid: test i2c_compare_byte with all properties.
647     {
648         json configFile = i2cCompareByteFile;
649         EXPECT_JSON_VALID(configFile);
650     }
651     // Valid: test i2c_compare_byte with all required properties.
652     {
653         json configFile = i2cCompareByteFile;
654         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("mask");
655         EXPECT_JSON_VALID(configFile);
656     }
657     // Invalid: test i2c_compare_byte with no register.
658     {
659         json configFile = i2cCompareByteFile;
660         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase(
661             "register");
662         EXPECT_JSON_INVALID(configFile, "Validation failed.",
663                             "u'register' is a required property");
664     }
665     // Invalid: test i2c_compare_byte with no value.
666     {
667         json configFile = i2cCompareByteFile;
668         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("value");
669         EXPECT_JSON_INVALID(configFile, "Validation failed.",
670                             "u'value' is a required property");
671     }
672     // Invalid: test i2c_compare_byte with property register wrong type.
673     {
674         json configFile = i2cCompareByteFile;
675         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
676             1;
677         EXPECT_JSON_INVALID(configFile, "Validation failed.",
678                             "1 is not of type u'string'");
679     }
680     // Invalid: test i2c_compare_byte with property value wrong type.
681     {
682         json configFile = i2cCompareByteFile;
683         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] = 1;
684         EXPECT_JSON_INVALID(configFile, "Validation failed.",
685                             "1 is not of type u'string'");
686     }
687     // Invalid: test i2c_compare_byte with property mask wrong type.
688     {
689         json configFile = i2cCompareByteFile;
690         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = 1;
691         EXPECT_JSON_INVALID(configFile, "Validation failed.",
692                             "1 is not of type u'string'");
693     }
694     // Invalid: test i2c_compare_byte with property register more than 2 hex
695     // digits.
696     {
697         json configFile = i2cCompareByteFile;
698         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
699             "0x820";
700         EXPECT_JSON_INVALID(configFile, "Validation failed.",
701                             "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
702     }
703     // Invalid: test i2c_compare_byte with property value more than 2 hex
704     // digits.
705     {
706         json configFile = i2cCompareByteFile;
707         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
708             "0x820";
709         EXPECT_JSON_INVALID(configFile, "Validation failed.",
710                             "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
711     }
712     // Invalid: test i2c_compare_byte with property mask more than 2 hex digits.
713     {
714         json configFile = i2cCompareByteFile;
715         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
716             "0x820";
717         EXPECT_JSON_INVALID(configFile, "Validation failed.",
718                             "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
719     }
720     // Invalid: test i2c_compare_byte with property register less than 2 hex
721     // digits.
722     {
723         json configFile = i2cCompareByteFile;
724         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
725             "0x8";
726         EXPECT_JSON_INVALID(configFile, "Validation failed.",
727                             "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
728     }
729     // Invalid: test i2c_compare_byte with property value less than 2 hex
730     // digits.
731     {
732         json configFile = i2cCompareByteFile;
733         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
734             "0x8";
735         EXPECT_JSON_INVALID(configFile, "Validation failed.",
736                             "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
737     }
738     // Invalid: test i2c_compare_byte with property mask less than 2 hex digits.
739     {
740         json configFile = i2cCompareByteFile;
741         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
742             "0x8";
743         EXPECT_JSON_INVALID(configFile, "Validation failed.",
744                             "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
745     }
746     // Invalid: test i2c_compare_byte with property register no leading prefix.
747     {
748         json configFile = i2cCompareByteFile;
749         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
750             "82";
751         EXPECT_JSON_INVALID(configFile, "Validation failed.",
752                             "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
753     }
754     // Invalid: test i2c_compare_byte with property value no leading prefix.
755     {
756         json configFile = i2cCompareByteFile;
757         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
758             "82";
759         EXPECT_JSON_INVALID(configFile, "Validation failed.",
760                             "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
761     }
762     // Invalid: test i2c_compare_byte with property mask no leading prefix.
763     {
764         json configFile = i2cCompareByteFile;
765         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = "82";
766         EXPECT_JSON_INVALID(configFile, "Validation failed.",
767                             "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
768     }
769     // Invalid: test i2c_compare_byte with property register invalid hex digit.
770     {
771         json configFile = i2cCompareByteFile;
772         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
773             "0xG1";
774         EXPECT_JSON_INVALID(configFile, "Validation failed.",
775                             "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
776     }
777     // Invalid: test i2c_compare_byte with property value invalid hex digit.
778     {
779         json configFile = i2cCompareByteFile;
780         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
781             "0xG1";
782         EXPECT_JSON_INVALID(configFile, "Validation failed.",
783                             "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
784     }
785     // Invalid: test i2c_compare_byte with property mask invalid hex digit.
786     {
787         json configFile = i2cCompareByteFile;
788         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
789             "0xG1";
790         EXPECT_JSON_INVALID(configFile, "Validation failed.",
791                             "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
792     }
793 }
794 TEST(ValidateRegulatorsConfigTest, I2CCompareBytes)
795 {
796     json i2cCompareBytesFile = validConfigFile;
797     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
798                        ["register"] = "0x82";
799     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
800                        ["values"] = {"0x02", "0x73"};
801     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
802                        ["masks"] = {"0x7F", "0x7F"};
803     // Valid: test i2c_compare_bytes.
804     {
805         json configFile = i2cCompareBytesFile;
806         EXPECT_JSON_VALID(configFile);
807     }
808     // Valid: test i2c_compare_bytes with all required properties.
809     {
810         json configFile = i2cCompareBytesFile;
811         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
812             "masks");
813         EXPECT_JSON_VALID(configFile);
814     }
815     // Invalid: test i2c_compare_bytes with no register.
816     {
817         json configFile = i2cCompareBytesFile;
818         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
819             "register");
820         EXPECT_JSON_INVALID(configFile, "Validation failed.",
821                             "u'register' is a required property");
822     }
823     // Invalid: test i2c_compare_bytes with no values.
824     {
825         json configFile = i2cCompareBytesFile;
826         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
827             "values");
828         EXPECT_JSON_INVALID(configFile, "Validation failed.",
829                             "u'values' is a required property");
830     }
831     // Invalid: test i2c_compare_bytes with property values as empty array.
832     {
833         json configFile = i2cCompareBytesFile;
834         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] =
835             json::array();
836         EXPECT_JSON_INVALID(configFile, "Validation failed.",
837                             "[] is too short");
838     }
839     // Invalid: test i2c_compare_bytes with property masks as empty array.
840     {
841         json configFile = i2cCompareBytesFile;
842         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] =
843             json::array();
844         EXPECT_JSON_INVALID(configFile, "Validation failed.",
845                             "[] is too short");
846     }
847     // Invalid: test i2c_compare_bytes with property register wrong type.
848     {
849         json configFile = i2cCompareBytesFile;
850         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
851             1;
852         EXPECT_JSON_INVALID(configFile, "Validation failed.",
853                             "1 is not of type u'string'");
854     }
855     // Invalid: test i2c_compare_bytes with property values wrong type.
856     {
857         json configFile = i2cCompareBytesFile;
858         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = 1;
859         EXPECT_JSON_INVALID(configFile, "Validation failed.",
860                             "1 is not of type u'array'");
861     }
862     // Invalid: test i2c_compare_bytes with property masks wrong type.
863     {
864         json configFile = i2cCompareBytesFile;
865         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = 1;
866         EXPECT_JSON_INVALID(configFile, "Validation failed.",
867                             "1 is not of type u'array'");
868     }
869     // Invalid: test i2c_compare_bytes with property register more than 2 hex
870     // digits.
871     {
872         json configFile = i2cCompareBytesFile;
873         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
874             "0x820";
875         EXPECT_JSON_INVALID(configFile, "Validation failed.",
876                             "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
877     }
878     // Invalid: test i2c_compare_bytes with property values more than 2 hex
879     // digits.
880     {
881         json configFile = i2cCompareBytesFile;
882         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
883             "0x820";
884         EXPECT_JSON_INVALID(configFile, "Validation failed.",
885                             "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
886     }
887     // Invalid: test i2c_compare_bytes with property masks more than 2 hex
888     // digits.
889     {
890         json configFile = i2cCompareBytesFile;
891         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
892             "0x820";
893         EXPECT_JSON_INVALID(configFile, "Validation failed.",
894                             "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
895     }
896     // Invalid: test i2c_compare_bytes with property register less than 2 hex
897     // digits.
898     {
899         json configFile = i2cCompareBytesFile;
900         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
901             "0x8";
902         EXPECT_JSON_INVALID(configFile, "Validation failed.",
903                             "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
904     }
905     // Invalid: test i2c_compare_bytes with property values less than 2 hex
906     // digits.
907     {
908         json configFile = i2cCompareBytesFile;
909         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
910             "0x8";
911         EXPECT_JSON_INVALID(configFile, "Validation failed.",
912                             "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
913     }
914     // Invalid: test i2c_compare_bytes with property masks less than 2 hex
915     // digits.
916     {
917         json configFile = i2cCompareBytesFile;
918         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
919             "0x8";
920         EXPECT_JSON_INVALID(configFile, "Validation failed.",
921                             "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
922     }
923     // Invalid: test i2c_compare_bytes with property register no leading prefix.
924     {
925         json configFile = i2cCompareBytesFile;
926         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
927             "82";
928         EXPECT_JSON_INVALID(configFile, "Validation failed.",
929                             "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
930     }
931     // Invalid: test i2c_compare_bytes with property values no leading prefix.
932     {
933         json configFile = i2cCompareBytesFile;
934         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
935             "82";
936         EXPECT_JSON_INVALID(configFile, "Validation failed.",
937                             "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
938     }
939     // Invalid: test i2c_compare_bytes with property masks no leading prefix.
940     {
941         json configFile = i2cCompareBytesFile;
942         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
943             "82";
944         EXPECT_JSON_INVALID(configFile, "Validation failed.",
945                             "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
946     }
947     // Invalid: test i2c_compare_bytes with property register invalid hex digit.
948     {
949         json configFile = i2cCompareBytesFile;
950         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
951             "0xG1";
952         EXPECT_JSON_INVALID(configFile, "Validation failed.",
953                             "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
954     }
955     // Invalid: test i2c_compare_bytes with property values invalid hex digit.
956     {
957         json configFile = i2cCompareBytesFile;
958         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
959             "0xG1";
960         EXPECT_JSON_INVALID(configFile, "Validation failed.",
961                             "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
962     }
963     // Invalid: test i2c_compare_bytes with property masks invalid hex digit.
964     {
965         json configFile = i2cCompareBytesFile;
966         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
967             "0xG1";
968         EXPECT_JSON_INVALID(configFile, "Validation failed.",
969                             "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
970     }
971 }
972 TEST(ValidateRegulatorsConfigTest, If)
973 {
974     json ifFile = validConfigFile;
975     ifFile["rules"][0]["actions"][1]["if"]["condition"]["run_rule"] =
976         "is_downlevel_regulator";
977     ifFile["rules"][0]["actions"][1]["if"]["then"][0]["run_rule"] =
978         "configure_downlevel_regulator";
979     ifFile["rules"][0]["actions"][1]["if"]["else"][0]["run_rule"] =
980         "configure_downlevel_regulator";
981     // Valid: test if.
982     {
983         json configFile = ifFile;
984         EXPECT_JSON_VALID(configFile);
985     }
986     // Valid: test if with required properties.
987     {
988         json configFile = ifFile;
989         configFile["rules"][0]["actions"][1]["if"].erase("else");
990         EXPECT_JSON_VALID(configFile);
991     }
992     // Invalid: test if with no property condition.
993     {
994         json configFile = ifFile;
995         configFile["rules"][0]["actions"][1]["if"].erase("condition");
996         EXPECT_JSON_INVALID(configFile, "Validation failed.",
997                             "u'condition' is a required property");
998     }
999     // Invalid: test if with no property then.
1000     {
1001         json configFile = ifFile;
1002         configFile["rules"][0]["actions"][1]["if"].erase("then");
1003         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1004                             "u'then' is a required property");
1005     }
1006     // Invalid: test if with property then empty array.
1007     {
1008         json configFile = ifFile;
1009         configFile["rules"][0]["actions"][1]["if"]["then"] = json::array();
1010         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1011                             "[] is too short");
1012     }
1013     // Invalid: test if with property else empty array.
1014     {
1015         json configFile = ifFile;
1016         configFile["rules"][0]["actions"][1]["if"]["else"] = json::array();
1017         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1018                             "[] is too short");
1019     }
1020     // Invalid: test if with property condition wrong type.
1021     {
1022         json configFile = ifFile;
1023         configFile["rules"][0]["actions"][1]["if"]["condition"] = 1;
1024         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1025                             "1 is not of type u'object'");
1026     }
1027     // Invalid: test if with property then wrong type.
1028     {
1029         json configFile = ifFile;
1030         configFile["rules"][0]["actions"][1]["if"]["then"] = 1;
1031         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1032                             "1 is not of type u'array'");
1033     }
1034     // Invalid: test if with property else wrong type.
1035     {
1036         json configFile = ifFile;
1037         configFile["rules"][0]["actions"][1]["if"]["else"] = 1;
1038         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1039                             "1 is not of type u'array'");
1040     }
1041 }
1042 TEST(ValidateRegulatorsConfigTest, Not)
1043 {
1044     json notFile = validConfigFile;
1045     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["register"] =
1046         "0xA0";
1047     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["value"] =
1048         "0xFF";
1049     // Valid: test not.
1050     {
1051         json configFile = notFile;
1052         EXPECT_JSON_VALID(configFile);
1053     }
1054     // Invalid: test not with wrong type.
1055     {
1056         json configFile = notFile;
1057         configFile["rules"][0]["actions"][1]["not"] = 1;
1058         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1059                             "1 is not of type u'object'");
1060     }
1061 }
1062 TEST(ValidateRegulatorsConfigTest, Or)
1063 {
1064     json orFile = validConfigFile;
1065     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["register"] =
1066         "0xA0";
1067     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["value"] =
1068         "0x00";
1069     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["register"] =
1070         "0xA1";
1071     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["value"] =
1072         "0x00";
1073     // Valid: test or.
1074     {
1075         json configFile = orFile;
1076         EXPECT_JSON_VALID(configFile);
1077     }
1078     // Invalid: test or with empty array.
1079     {
1080         json configFile = orFile;
1081         configFile["rules"][0]["actions"][1]["or"] = json::array();
1082         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1083                             "[] is too short");
1084     }
1085     // Invalid: test or with wrong type.
1086     {
1087         json configFile = orFile;
1088         configFile["rules"][0]["actions"][1]["or"] = 1;
1089         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1090                             "1 is not of type u'array'");
1091     }
1092 }
1093 TEST(ValidateRegulatorsConfigTest, PmbusReadSensor)
1094 {
1095     json pmbusReadSensorFile = validConfigFile;
1096     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1097         "vout";
1098     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1099                        ["command"] = "0x8B";
1100     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1101                        ["format"] = "linear_16";
1102     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1103                        ["exponent"] = -8;
1104     // Valid: test pmbus_read_sensor.
1105     {
1106         json configFile = pmbusReadSensorFile;
1107         EXPECT_JSON_VALID(configFile);
1108     }
1109     // Valid: test pmbus_read_sensor with required properties.
1110     {
1111         json configFile = pmbusReadSensorFile;
1112         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1113             "exponent");
1114         EXPECT_JSON_VALID(configFile);
1115     }
1116     // Invalid: test pmbus_read_sensor with no type.
1117     {
1118         json configFile = pmbusReadSensorFile;
1119         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase("type");
1120         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1121                             "u'type' is a required property");
1122     }
1123     // Invalid: test pmbus_read_sensor with no command.
1124     {
1125         json configFile = pmbusReadSensorFile;
1126         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1127             "command");
1128         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1129                             "u'command' is a required property");
1130     }
1131     // Invalid: test pmbus_read_sensor with no format.
1132     {
1133         json configFile = pmbusReadSensorFile;
1134         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1135             "format");
1136         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1137                             "u'format' is a required property");
1138     }
1139     // Invalid: test pmbus_read_sensor with property type wrong type.
1140     {
1141         json configFile = pmbusReadSensorFile;
1142         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1143             true;
1144         EXPECT_JSON_INVALID(
1145             configFile, "Validation failed.",
1146             "True is not one of [u'iout', u'iout_peak', u'iout_valley', "
1147             "u'pout', u'temperature', u'temperature_peak', u'vout', "
1148             "u'vout_peak', u'vout_valley']");
1149     }
1150     // Invalid: test pmbus_read_sensor with property command wrong type.
1151     {
1152         json configFile = pmbusReadSensorFile;
1153         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1154             true;
1155         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1156                             "True is not of type u'string'");
1157     }
1158     // Invalid: test pmbus_read_sensor with property format wrong type.
1159     {
1160         json configFile = pmbusReadSensorFile;
1161         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1162             true;
1163         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1164                             "True is not one of [u'linear_11', u'linear_16']");
1165     }
1166     // Invalid: test pmbus_read_sensor with property exponent wrong type.
1167     {
1168         json configFile = pmbusReadSensorFile;
1169         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["exponent"] =
1170             true;
1171         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1172                             "True is not of type u'integer'");
1173     }
1174     // Invalid: test pmbus_read_sensor with property type wrong format.
1175     {
1176         json configFile = pmbusReadSensorFile;
1177         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1178             "foo";
1179         EXPECT_JSON_INVALID(
1180             configFile, "Validation failed.",
1181             "u'foo' is not one of [u'iout', u'iout_peak', u'iout_valley', "
1182             "u'pout', u'temperature', u'temperature_peak', u'vout', "
1183             "u'vout_peak', u'vout_valley']");
1184     }
1185     // Invalid: test pmbus_read_sensor with property command wrong format.
1186     {
1187         json configFile = pmbusReadSensorFile;
1188         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1189             "0x8B0";
1190         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1191                             "u'0x8B0' does not match u'^0x[0-9a-fA-F]{2}$'");
1192     }
1193     // Invalid: test pmbus_read_sensor with property format wrong format.
1194     {
1195         json configFile = pmbusReadSensorFile;
1196         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1197             "foo";
1198         EXPECT_JSON_INVALID(
1199             configFile, "Validation failed.",
1200             "u'foo' is not one of [u'linear_11', u'linear_16']");
1201     }
1202 }
1203 TEST(ValidateRegulatorsConfigTest, PmbusWriteVoutCommand)
1204 {
1205     json pmbusWriteVoutCommandFile = validConfigFile;
1206     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1207                              ["pmbus_write_vout_command"]["volts"] = 1.03;
1208     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1209                              ["pmbus_write_vout_command"]["format"] = "linear";
1210     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1211                              ["pmbus_write_vout_command"]["exponent"] = -8;
1212     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1213                              ["pmbus_write_vout_command"]["is_verified"] = true;
1214     // Valid: test pmbus_write_vout_command.
1215     {
1216         json configFile = pmbusWriteVoutCommandFile;
1217         EXPECT_JSON_VALID(configFile);
1218     }
1219     // Valid: test pmbus_write_vout_command with required properties.
1220     {
1221         json configFile = pmbusWriteVoutCommandFile;
1222         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1223             "volts");
1224         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1225             "exponent");
1226         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1227             "is_verified");
1228         EXPECT_JSON_VALID(configFile);
1229     }
1230     // Invalid: test pmbus_write_vout_command with no format.
1231     {
1232         json configFile = pmbusWriteVoutCommandFile;
1233         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1234             "format");
1235         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1236                             "u'format' is a required property");
1237     }
1238     // Invalid: test pmbus_write_vout_command with property volts wrong type.
1239     {
1240         json configFile = pmbusWriteVoutCommandFile;
1241         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1242                   ["volts"] = true;
1243         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1244                             "True is not of type u'number'");
1245     }
1246     // Invalid: test pmbus_write_vout_command with property format wrong type.
1247     {
1248         json configFile = pmbusWriteVoutCommandFile;
1249         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1250                   ["format"] = true;
1251         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1252                             "True is not one of [u'linear']");
1253     }
1254     // Invalid: test pmbus_write_vout_command with property exponent wrong type.
1255     {
1256         json configFile = pmbusWriteVoutCommandFile;
1257         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1258                   ["exponent"] = 1.3;
1259         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1260                             "1.3 is not of type u'integer'");
1261     }
1262     // Invalid: test pmbus_write_vout_command with property is_verified wrong
1263     // type.
1264     {
1265         json configFile = pmbusWriteVoutCommandFile;
1266         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1267                   ["is_verified"] = 1;
1268         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1269                             "1 is not of type u'boolean'");
1270     }
1271     // Invalid: test pmbus_write_vout_command with property format wrong format.
1272     {
1273         json configFile = pmbusWriteVoutCommandFile;
1274         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1275                   ["format"] = "foo";
1276         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1277                             "u'foo' is not one of [u'linear']");
1278     }
1279 }
1280 TEST(ValidateRegulatorsConfigTest, RunRule)
1281 {
1282     json runRuleFile = validConfigFile;
1283     runRuleFile["rules"][0]["actions"][1]["run_rule"] = "set_voltage_rule1";
1284     // Valid: test run_rule.
1285     {
1286         json configFile = runRuleFile;
1287         EXPECT_JSON_VALID(configFile);
1288     }
1289     // Invalid: test run_rule wrong type.
1290     {
1291         json configFile = runRuleFile;
1292         configFile["rules"][0]["actions"][1]["run_rule"] = true;
1293         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1294                             "True is not of type u'string'");
1295     }
1296     // Invalid: test run_rule wrong format.
1297     {
1298         json configFile = runRuleFile;
1299         configFile["rules"][0]["actions"][1]["run_rule"] = "set_voltage_rule%";
1300         EXPECT_JSON_INVALID(
1301             configFile, "Validation failed.",
1302             "u'set_voltage_rule%' does not match u'^[A-Za-z0-9_]+$'");
1303     }
1304 }
1305 TEST(ValidateRegulatorsConfigTest, SetDevice)
1306 {
1307     json setDeviceFile = validConfigFile;
1308     setDeviceFile["rules"][0]["actions"][1]["set_device"] = "io_expander2";
1309     // Valid: test set_device.
1310     {
1311         json configFile = setDeviceFile;
1312         EXPECT_JSON_VALID(configFile);
1313     }
1314     // Invalid: test set_device wrong type.
1315     {
1316         json configFile = setDeviceFile;
1317         configFile["rules"][0]["actions"][1]["set_device"] = true;
1318         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1319                             "True is not of type u'string'");
1320     }
1321     // Invalid: test set_device wrong format.
1322     {
1323         json configFile = setDeviceFile;
1324         configFile["rules"][0]["actions"][1]["set_device"] = "io_expander2%";
1325         EXPECT_JSON_INVALID(
1326             configFile, "Validation failed.",
1327             "u'io_expander2%' does not match u'^[A-Za-z0-9_]+$'");
1328     }
1329 }
1330