xref: /openbmc/phosphor-power/phosphor-regulators/test/validate-regulators-config_tests.cpp (revision 358c417a577146aa00669d77cf11c1f82ea2260c)
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/stat.h>
20 #include <sys/wait.h>
21 
22 #include <nlohmann/json.hpp>
23 
24 #include <fstream>
25 
26 #include <gtest/gtest.h>
27 
28 #define EXPECT_FILE_VALID(configFile) expectFileValid(configFile)
29 #define EXPECT_FILE_INVALID(configFile, expectedErrorMessage,                  \
30                             expectedOutputMessage)                             \
31     expectFileInvalid(configFile, expectedErrorMessage, expectedOutputMessage)
32 #define EXPECT_JSON_VALID(configFileJson) expectJsonValid(configFileJson)
33 #define EXPECT_JSON_INVALID(configFileJson, expectedErrorMessage,              \
34                             expectedOutputMessage)                             \
35     expectJsonInvalid(configFileJson, expectedErrorMessage,                    \
36                       expectedOutputMessage)
37 
38 using json = nlohmann::json;
39 
40 const json validConfigFile = R"(
41     {
42       "comments": [ "Config file for a FooBar one-chassis system" ],
43 
44       "rules": [
45         {
46           "comments": [ "Sets output voltage for a PMBus regulator rail" ],
47           "id": "set_voltage_rule",
48           "actions": [
49             {
50               "pmbus_write_vout_command": {
51                 "format": "linear"
52               }
53             }
54           ]
55         },
56         {
57           "comments": [ "Reads sensors from a PMBus regulator rail" ],
58           "id": "read_sensors_rule",
59           "actions": [
60             {
61               "comments": [ "Read output voltage from READ_VOUT." ],
62               "pmbus_read_sensor": {
63                 "type": "vout",
64                 "command": "0x8B",
65                 "format": "linear_16"
66               }
67             }
68           ]
69         }
70       ],
71 
72       "chassis": [
73         {
74           "comments": [ "Chassis number 1 containing CPUs and memory" ],
75           "number": 1,
76           "devices": [
77             {
78               "comments": [ "IR35221 regulator producing the Vdd rail" ],
79               "id": "vdd_regulator",
80               "is_regulator": true,
81               "fru": "/system/chassis/motherboard/regulator1",
82               "i2c_interface": {
83                 "bus": 1,
84                 "address": "0x70"
85               },
86               "rails": [
87                 {
88                   "comments": [ "Vdd rail" ],
89                   "id": "vdd",
90                   "configuration": {
91                     "volts": 1.03,
92                     "rule_id": "set_voltage_rule"
93                   },
94                   "sensor_monitoring": {
95                     "rule_id": "read_sensors_rule"
96                   }
97                 }
98               ]
99             }
100           ]
101         }
102       ]
103     }
104 )"_json;
105 
106 class TmpFile
107 {
108   public:
109     TmpFile()
110     {
111         int fd = mkstemp(fileName);
112         if (fd == -1)
113         {
114             perror("Can't create temporary file");
115         }
116         close(fd);
117     }
118 
119     std::string getName()
120     {
121         return fileName;
122     }
123 
124     ~TmpFile()
125     {
126         unlink(fileName);
127     }
128 
129   private:
130     char fileName[17] = "/tmp/temp-XXXXXX";
131 };
132 
133 std::string getValidationToolCommand(const std::string& configFileName)
134 {
135     std::string command =
136         "../phosphor-regulators/tools/validate-regulators-config.py -s \
137          ../phosphor-regulators/schema/config_schema.json -c ";
138     command += configFileName;
139     return command;
140 }
141 
142 int runToolForOutputWithCommand(std::string command,
143                                 std::string& standardOutput,
144                                 std::string& standardError)
145 {
146     // run the validation tool with the temporary file and return the output
147     // of the validation tool.
148     TmpFile tmpFile;
149     command += " 2> " + tmpFile.getName();
150     // get the jsonschema print from validation tool.
151     char buffer[256];
152     std::string result;
153     // to get the stdout from the validation tool.
154     FILE* pipe = popen(command.c_str(), "r");
155     if (!pipe)
156     {
157         throw std::runtime_error("popen() failed!");
158     }
159     while (!std::feof(pipe))
160     {
161         if (fgets(buffer, sizeof buffer, pipe) != NULL)
162         {
163             result += buffer;
164         }
165     }
166     int returnValue = pclose(pipe);
167     // Check if pclose() failed
168     if (returnValue == -1)
169     {
170         // unable to close pipe.  Print error and exit function.
171         throw std::runtime_error("pclose() failed!");
172     }
173     std::string firstLine = result.substr(0, result.find('\n'));
174     standardOutput = firstLine;
175     // Get command exit status from return value
176     int exitStatus = WEXITSTATUS(returnValue);
177 
178     // Read the standardError from tmpFile.
179     std::ifstream input(tmpFile.getName().c_str());
180     std::string line;
181 
182     if (std::getline(input, line))
183     {
184         standardError = line;
185     }
186 
187     return exitStatus;
188 }
189 
190 int runToolForOutput(const std::string& configFileName, std::string& output,
191                      std::string& error)
192 {
193     std::string command = getValidationToolCommand(configFileName);
194     return runToolForOutputWithCommand(command, output, error);
195 }
196 
197 void expectFileValid(const std::string& configFileName)
198 {
199     std::string errorMessage;
200     std::string outputMessage;
201     EXPECT_EQ(runToolForOutput(configFileName, outputMessage, errorMessage), 0);
202     EXPECT_EQ(errorMessage, "");
203     EXPECT_EQ(outputMessage, "");
204 }
205 
206 void expectFileInvalid(const std::string& configFileName,
207                        const std::string& expectedErrorMessage,
208                        const std::string& expectedOutputMessage)
209 {
210     std::string errorMessage;
211     std::string outputMessage;
212     EXPECT_EQ(runToolForOutput(configFileName, outputMessage, errorMessage), 1);
213     EXPECT_EQ(errorMessage, expectedErrorMessage);
214     EXPECT_EQ(outputMessage, expectedOutputMessage);
215 }
216 
217 void writeDataToFile(const json configFileJson, std::string fileName)
218 {
219     std::string jsonData = configFileJson.dump();
220     std::ofstream out(fileName);
221     out << jsonData;
222     out.close();
223 }
224 
225 void expectJsonValid(const json configFileJson)
226 {
227     std::string fileName;
228     TmpFile tmpFile;
229     fileName = tmpFile.getName();
230     writeDataToFile(configFileJson, fileName);
231 
232     EXPECT_FILE_VALID(fileName);
233 }
234 
235 void expectJsonInvalid(const json configFileJson,
236                        const std::string& expectedErrorMessage,
237                        const std::string& expectedOutputMessage)
238 {
239     std::string fileName;
240     TmpFile tmpFile;
241     fileName = tmpFile.getName();
242     writeDataToFile(configFileJson, fileName);
243 
244     EXPECT_FILE_INVALID(fileName, expectedErrorMessage, expectedOutputMessage);
245 }
246 
247 void expectCommandLineSyntax(const std::string& expectedErrorMessage,
248                              const std::string& expectedOutputMessage,
249                              std::string command, int status)
250 {
251     std::string errorMessage;
252     std::string outputMessage;
253     EXPECT_EQ(runToolForOutputWithCommand(command, outputMessage, errorMessage),
254               status);
255     EXPECT_EQ(errorMessage, expectedErrorMessage);
256     EXPECT_EQ(outputMessage, expectedOutputMessage);
257 }
258 
259 TEST(ValidateRegulatorsConfigTest, And)
260 {
261     // Valid.
262     {
263         json configFile = validConfigFile;
264         json andAction =
265             R"(
266                 {
267                  "and": [
268                     { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
269                     { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
270                   ]
271                 }
272             )"_json;
273         configFile["rules"][0]["actions"].push_back(andAction);
274         EXPECT_JSON_VALID(configFile);
275     }
276 
277     // Invalid: actions property value is an empty array.
278     {
279         json configFile = validConfigFile;
280         json andAction =
281             R"(
282                 {
283                  "and": []
284                 }
285             )"_json;
286         configFile["rules"][0]["actions"].push_back(andAction);
287         EXPECT_JSON_INVALID(configFile, "Validation failed.",
288                             "[] is too short");
289     }
290 
291     // Invalid: actions property has incorrect value data type.
292     {
293         json configFile = validConfigFile;
294         json andAction =
295             R"(
296                 {
297                  "and": true
298                 }
299             )"_json;
300         configFile["rules"][0]["actions"].push_back(andAction);
301         EXPECT_JSON_INVALID(configFile, "Validation failed.",
302                             "True is not of type 'array'");
303     }
304 
305     // Invalid: actions property value contains wrong element type
306     {
307         json configFile = validConfigFile;
308         json andAction =
309             R"(
310                 {
311                  "and": ["foo"]
312                 }
313             )"_json;
314         configFile["rules"][0]["actions"].push_back(andAction);
315         EXPECT_JSON_INVALID(configFile, "Validation failed.",
316                             "'foo' is not of type 'object'");
317     }
318 }
319 TEST(ValidateRegulatorsConfigTest, Chassis)
320 {
321     // Valid: test chassis.
322     {
323         json configFile = validConfigFile;
324         EXPECT_JSON_VALID(configFile);
325     }
326     // Valid: test chassis with required properties.
327     {
328         json configFile = validConfigFile;
329         configFile["chassis"][0].erase("comments");
330         configFile["chassis"][0].erase("devices");
331         EXPECT_JSON_VALID(configFile);
332     }
333     // Invalid: test chassis with no number.
334     {
335         json configFile = validConfigFile;
336         configFile["chassis"][0].erase("number");
337         EXPECT_JSON_INVALID(configFile, "Validation failed.",
338                             "'number' is a required property");
339     }
340     // Invalid: test chassis with property comments wrong type.
341     {
342         json configFile = validConfigFile;
343         configFile["chassis"][0]["comments"] = true;
344         EXPECT_JSON_INVALID(configFile, "Validation failed.",
345                             "True is not of type 'array'");
346     }
347     // Invalid: test chassis with property number wrong type.
348     {
349         json configFile = validConfigFile;
350         configFile["chassis"][0]["number"] = 1.3;
351         EXPECT_JSON_INVALID(configFile, "Validation failed.",
352                             "1.3 is not of type 'integer'");
353     }
354     // Invalid: test chassis with property devices wrong type.
355     {
356         json configFile = validConfigFile;
357         configFile["chassis"][0]["devices"] = true;
358         EXPECT_JSON_INVALID(configFile, "Validation failed.",
359                             "True is not of type 'array'");
360     }
361     // Invalid: test chassis with property comments empty array.
362     {
363         json configFile = validConfigFile;
364         configFile["chassis"][0]["comments"] = json::array();
365         EXPECT_JSON_INVALID(configFile, "Validation failed.",
366                             "[] is too short");
367     }
368     // Invalid: test chassis with property devices empty array.
369     {
370         json configFile = validConfigFile;
371         configFile["chassis"][0]["devices"] = json::array();
372         EXPECT_JSON_INVALID(configFile, "Validation failed.",
373                             "[] is too short");
374     }
375     // Invalid: test chassis with property number less than 1.
376     {
377         json configFile = validConfigFile;
378         configFile["chassis"][0]["number"] = 0;
379         EXPECT_JSON_INVALID(configFile, "Validation failed.",
380                             "0 is less than the minimum of 1");
381     }
382 }
383 TEST(ValidateRegulatorsConfigTest, ComparePresence)
384 {
385     json comparePresenceFile = validConfigFile;
386     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
387         "/system/chassis/motherboard/regulator2";
388     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
389         true;
390     // Valid.
391     {
392         json configFile = comparePresenceFile;
393         EXPECT_JSON_VALID(configFile);
394     }
395 
396     // Invalid: no FRU property.
397     {
398         json configFile = comparePresenceFile;
399         configFile["rules"][0]["actions"][1]["compare_presence"].erase("fru");
400         EXPECT_JSON_INVALID(configFile, "Validation failed.",
401                             "'fru' is a required property");
402     }
403 
404     // Invalid: FRU property length is string less than 1.
405     {
406         json configFile = comparePresenceFile;
407         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = "";
408         EXPECT_JSON_INVALID(configFile, "Validation failed.",
409                             "'' is too short");
410     }
411 
412     // Invalid: no value property.
413     {
414         json configFile = comparePresenceFile;
415         configFile["rules"][0]["actions"][1]["compare_presence"].erase("value");
416         EXPECT_JSON_INVALID(configFile, "Validation failed.",
417                             "'value' is a required property");
418     }
419 
420     // Invalid: value property type is not boolean.
421     {
422         json configFile = comparePresenceFile;
423         configFile["rules"][0]["actions"][1]["compare_presence"]["value"] = "1";
424         EXPECT_JSON_INVALID(configFile, "Validation failed.",
425                             "'1' is not of type 'boolean'");
426     }
427 
428     // Invalid: FRU property type is not string.
429     {
430         json configFile = comparePresenceFile;
431         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = 1;
432         EXPECT_JSON_INVALID(configFile, "Validation failed.",
433                             "1 is not of type 'string'");
434     }
435 }
436 TEST(ValidateRegulatorsConfigTest, CompareVpd)
437 {
438     json compareVpdFile = validConfigFile;
439     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
440         "/system/chassis/motherboard/regulator2";
441     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
442     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
443 
444     // Valid.
445     {
446         json configFile = compareVpdFile;
447         EXPECT_JSON_VALID(configFile);
448     }
449 
450     // Invalid: no FRU property.
451     {
452         json configFile = compareVpdFile;
453         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("fru");
454         EXPECT_JSON_INVALID(configFile, "Validation failed.",
455                             "'fru' is a required property");
456     }
457 
458     // Invalid: no keyword property.
459     {
460         json configFile = compareVpdFile;
461         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("keyword");
462         EXPECT_JSON_INVALID(configFile, "Validation failed.",
463                             "'keyword' is a required property");
464     }
465 
466     // Invalid: no value property.
467     {
468         json configFile = compareVpdFile;
469         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("value");
470         EXPECT_JSON_INVALID(configFile, "Validation failed.",
471                             "'value' is a required property");
472     }
473 
474     // Invalid: property FRU wrong type.
475     {
476         json configFile = compareVpdFile;
477         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = 1;
478         EXPECT_JSON_INVALID(configFile, "Validation failed.",
479                             "1 is not of type 'string'");
480     }
481 
482     // Invalid: property FRU is string less than 1.
483     {
484         json configFile = compareVpdFile;
485         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = "";
486         EXPECT_JSON_INVALID(configFile, "Validation failed.",
487                             "'' is too short");
488     }
489 
490     // Invalid: property keyword is not "CCIN", "Manufacturer", "Model",
491     // "PartNumber"
492     {
493         json configFile = compareVpdFile;
494         configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] =
495             "Number";
496         EXPECT_JSON_INVALID(configFile, "Validation failed.",
497                             "'Number' is not one of ['CCIN', "
498                             "'Manufacturer', 'Model', 'PartNumber']");
499     }
500 
501     // Invalid: property value wrong type.
502     {
503         json configFile = compareVpdFile;
504         configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = 1;
505         EXPECT_JSON_INVALID(configFile, "Validation failed.",
506                             "1 is not of type 'string'");
507     }
508 }
509 TEST(ValidateRegulatorsConfigTest, Configuration)
510 {
511     json configurationFile = validConfigFile;
512     configurationFile["chassis"][0]["devices"][0]["configuration"]["comments"]
513                      [0] = "Set rail to 1.25V using standard rule";
514     configurationFile["chassis"][0]["devices"][0]["configuration"]["volts"] =
515         1.25;
516     configurationFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
517         "set_voltage_rule";
518     // Valid: test configuration with property rule_id and with no actions.
519     {
520         json configFile = configurationFile;
521         EXPECT_JSON_VALID(configFile);
522     }
523     // Valid: test configuration with property actions and with no rule_id.
524     {
525         json configFile = configurationFile;
526         configFile["chassis"][0]["devices"][0]["configuration"].erase(
527             "rule_id");
528         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
529                   ["compare_presence"]["fru"] =
530                       "/system/chassis/motherboard/cpu3";
531         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
532                   ["compare_presence"]["value"] = true;
533         EXPECT_JSON_VALID(configFile);
534     }
535     // Valid: comments not specified (optional property).
536     {
537         json configFile = configurationFile;
538         configFile["chassis"][0]["devices"][0]["configuration"].erase(
539             "comments");
540         EXPECT_JSON_VALID(configFile);
541     }
542     // Valid: volts not specified (optional property).
543     {
544         json configFile = configurationFile;
545         configFile["chassis"][0]["devices"][0]["configuration"].erase("volts");
546         EXPECT_JSON_VALID(configFile);
547     }
548     // Valid: configuration is property of a rail (vs. a device).
549     {
550         json configFile = validConfigFile;
551         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
552                   ["comments"][0] = "Set rail to 1.25V using standard rule";
553         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
554                   ["volts"] = 1.25;
555         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
556                   ["rule_id"] = "set_voltage_rule";
557         EXPECT_JSON_VALID(configFile);
558     }
559     // Invalid: comments property has wrong data type (not an array).
560     {
561         json configFile = configurationFile;
562         configFile["chassis"][0]["devices"][0]["configuration"]["comments"] = 1;
563         EXPECT_JSON_INVALID(configFile, "Validation failed.",
564                             "1 is not of type 'array'");
565     }
566     // Invalid: test configuration with both actions and rule_id properties.
567     {
568         json configFile = configurationFile;
569         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
570                   ["compare_presence"]["fru"] =
571                       "/system/chassis/motherboard/cpu3";
572         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
573                   ["compare_presence"]["value"] = true;
574         EXPECT_JSON_INVALID(
575             configFile, "Validation failed.",
576             "{'actions': [{'compare_presence': {'fru': "
577             "'/system/chassis/motherboard/cpu3', 'value': True}}], 'comments': "
578             "['Set rail to 1.25V using standard rule'], 'rule_id': "
579             "'set_voltage_rule', 'volts': 1.25} is valid under each of "
580             "{'required': ['actions']}, {'required': ['rule_id']}");
581     }
582     // Invalid: test configuration with no rule_id and actions.
583     {
584         json configFile = configurationFile;
585         configFile["chassis"][0]["devices"][0]["configuration"].erase(
586             "rule_id");
587         EXPECT_JSON_INVALID(configFile, "Validation failed.",
588                             "'rule_id' is a required property");
589     }
590     // Invalid: test configuration with property volts wrong type.
591     {
592         json configFile = configurationFile;
593         configFile["chassis"][0]["devices"][0]["configuration"]["volts"] = true;
594         EXPECT_JSON_INVALID(configFile, "Validation failed.",
595                             "True is not of type 'number'");
596     }
597     // Invalid: test configuration with property rule_id wrong type.
598     {
599         json configFile = configurationFile;
600         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
601             true;
602         EXPECT_JSON_INVALID(configFile, "Validation failed.",
603                             "True is not of type 'string'");
604     }
605     // Invalid: test configuration with property actions wrong type.
606     {
607         json configFile = configurationFile;
608         configFile["chassis"][0]["devices"][0]["configuration"].erase(
609             "rule_id");
610         configFile["chassis"][0]["devices"][0]["configuration"]["actions"] =
611             true;
612         EXPECT_JSON_INVALID(configFile, "Validation failed.",
613                             "True is not of type 'array'");
614     }
615     // Invalid: test configuration with property comments empty array.
616     {
617         json configFile = configurationFile;
618         configFile["chassis"][0]["devices"][0]["configuration"]["comments"] =
619             json::array();
620         EXPECT_JSON_INVALID(configFile, "Validation failed.",
621                             "[] is too short");
622     }
623     // Invalid: test configuration with property rule_id wrong format.
624     {
625         json configFile = configurationFile;
626         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
627             "id!";
628         EXPECT_JSON_INVALID(configFile, "Validation failed.",
629                             "'id!' does not match '^[A-Za-z0-9_]+$'");
630     }
631     // Invalid: test configuration with property actions empty array.
632     {
633         json configFile = configurationFile;
634         configFile["chassis"][0]["devices"][0]["configuration"].erase(
635             "rule_id");
636         configFile["chassis"][0]["devices"][0]["configuration"]["actions"] =
637             json::array();
638         EXPECT_JSON_INVALID(configFile, "Validation failed.",
639                             "[] is too short");
640     }
641 }
642 TEST(ValidateRegulatorsConfigTest, Device)
643 {
644 
645     // Valid: test devices.
646     {
647         json configFile = validConfigFile;
648         EXPECT_JSON_VALID(configFile);
649     }
650     // Valid: test devices with required properties.
651     {
652         json configFile = validConfigFile;
653         configFile["chassis"][0]["devices"][0].erase("comments");
654         configFile["chassis"][0]["devices"][0].erase("presence_detection");
655         configFile["chassis"][0]["devices"][0].erase("configuration");
656         configFile["chassis"][0]["devices"][0].erase("rails");
657         EXPECT_JSON_VALID(configFile);
658     }
659     // Invalid: test devices with no id.
660     {
661         json configFile = validConfigFile;
662         configFile["chassis"][0]["devices"][0].erase("id");
663         EXPECT_JSON_INVALID(configFile, "Validation failed.",
664                             "'id' is a required property");
665     }
666     // Invalid: test devices with no is_regulator.
667     {
668         json configFile = validConfigFile;
669         configFile["chassis"][0]["devices"][0].erase("is_regulator");
670         EXPECT_JSON_INVALID(configFile, "Validation failed.",
671                             "'is_regulator' is a required property");
672     }
673     // Invalid: test devices with no fru.
674     {
675         json configFile = validConfigFile;
676         configFile["chassis"][0]["devices"][0].erase("fru");
677         EXPECT_JSON_INVALID(configFile, "Validation failed.",
678                             "'fru' is a required property");
679     }
680     // Invalid: test devices with no i2c_interface.
681     {
682         json configFile = validConfigFile;
683         configFile["chassis"][0]["devices"][0].erase("i2c_interface");
684         EXPECT_JSON_INVALID(configFile, "Validation failed.",
685                             "'i2c_interface' is a required property");
686     }
687     // Invalid: test devices with property comments wrong type.
688     {
689         json configFile = validConfigFile;
690         configFile["chassis"][0]["devices"][0]["comments"] = true;
691         EXPECT_JSON_INVALID(configFile, "Validation failed.",
692                             "True is not of type 'array'");
693     }
694     // Invalid: test devices with property id wrong type.
695     {
696         json configFile = validConfigFile;
697         configFile["chassis"][0]["devices"][0]["id"] = true;
698         EXPECT_JSON_INVALID(configFile, "Validation failed.",
699                             "True is not of type 'string'");
700     }
701     // Invalid: test devices with property is_regulator wrong type.
702     {
703         json configFile = validConfigFile;
704         configFile["chassis"][0]["devices"][0]["is_regulator"] = 1;
705         EXPECT_JSON_INVALID(configFile, "Validation failed.",
706                             "1 is not of type 'boolean'");
707     }
708     // Invalid: test devices with property fru wrong type.
709     {
710         json configFile = validConfigFile;
711         configFile["chassis"][0]["devices"][0]["fru"] = true;
712         EXPECT_JSON_INVALID(configFile, "Validation failed.",
713                             "True is not of type 'string'");
714     }
715     // Invalid: test devices with property i2c_interface wrong type.
716     {
717         json configFile = validConfigFile;
718         configFile["chassis"][0]["devices"][0]["i2c_interface"] = true;
719         EXPECT_JSON_INVALID(configFile, "Validation failed.",
720                             "True is not of type 'object'");
721     }
722     // Invalid: test devices with property presence_detection wrong
723     // type.
724     {
725         json configFile = validConfigFile;
726         configFile["chassis"][0]["devices"][0]["presence_detection"] = true;
727         EXPECT_JSON_INVALID(configFile, "Validation failed.",
728                             "True is not of type 'object'");
729     }
730     // Invalid: test devices with property configuration wrong type.
731     {
732         json configFile = validConfigFile;
733         configFile["chassis"][0]["devices"][0]["configuration"] = true;
734         EXPECT_JSON_INVALID(configFile, "Validation failed.",
735                             "True is not of type 'object'");
736     }
737     // Invalid: test devices with property rails wrong type.
738     {
739         json configFile = validConfigFile;
740         configFile["chassis"][0]["devices"][0]["rails"] = true;
741         EXPECT_JSON_INVALID(configFile, "Validation failed.",
742                             "True is not of type 'array'");
743     }
744     // Invalid: test devices with property comments empty array.
745     {
746         json configFile = validConfigFile;
747         configFile["chassis"][0]["devices"][0]["comments"] = json::array();
748         EXPECT_JSON_INVALID(configFile, "Validation failed.",
749                             "[] is too short");
750     }
751     // Invalid: test devices with property fru length less than 1.
752     {
753         json configFile = validConfigFile;
754         configFile["chassis"][0]["devices"][0]["fru"] = "";
755         EXPECT_JSON_INVALID(configFile, "Validation failed.",
756                             "'' is too short");
757     }
758     // Invalid: test devices with property id wrong format.
759     {
760         json configFile = validConfigFile;
761         configFile["chassis"][0]["devices"][0]["id"] = "id#";
762         EXPECT_JSON_INVALID(configFile, "Validation failed.",
763                             "'id#' does not match '^[A-Za-z0-9_]+$'");
764     }
765     // Invalid: test devices with property rails empty array.
766     {
767         json configFile = validConfigFile;
768         configFile["chassis"][0]["devices"][0]["rails"] = json::array();
769         EXPECT_JSON_INVALID(configFile, "Validation failed.",
770                             "[] is too short");
771     }
772 }
773 TEST(ValidateRegulatorsConfigTest, I2CCompareBit)
774 {
775     json i2cCompareBitFile = validConfigFile;
776     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
777         "0xA0";
778     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
779         3;
780     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
781     // Valid: test rule actions i2c_compare_bit.
782     {
783         json configFile = i2cCompareBitFile;
784         EXPECT_JSON_VALID(configFile);
785     }
786     // Invalid: test i2c_compare_bit with no register.
787     {
788         json configFile = i2cCompareBitFile;
789         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
790             "register");
791         EXPECT_JSON_INVALID(configFile, "Validation failed.",
792                             "'register' is a required property");
793     }
794     // Invalid: test i2c_compare_bit with no position.
795     {
796         json configFile = i2cCompareBitFile;
797         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
798             "position");
799         EXPECT_JSON_INVALID(configFile, "Validation failed.",
800                             "'position' is a required property");
801     }
802     // Invalid: test i2c_compare_bit with no value.
803     {
804         json configFile = i2cCompareBitFile;
805         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase("value");
806         EXPECT_JSON_INVALID(configFile, "Validation failed.",
807                             "'value' is a required property");
808     }
809     // Invalid: test i2c_compare_bit with register wrong type.
810     {
811         json configFile = i2cCompareBitFile;
812         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] = 1;
813         EXPECT_JSON_INVALID(configFile, "Validation failed.",
814                             "1 is not of type 'string'");
815     }
816     // Invalid: test i2c_compare_bit with register wrong format.
817     {
818         json configFile = i2cCompareBitFile;
819         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
820             "0xA00";
821         EXPECT_JSON_INVALID(configFile, "Validation failed.",
822                             "'0xA00' does not match '^0x[0-9A-Fa-f]{2}$'");
823     }
824     // Invalid: test i2c_compare_bit with position wrong type.
825     {
826         json configFile = i2cCompareBitFile;
827         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
828             3.1;
829         EXPECT_JSON_INVALID(configFile, "Validation failed.",
830                             "3.1 is not of type 'integer'");
831     }
832     // Invalid: test i2c_compare_bit with position greater than 7.
833     {
834         json configFile = i2cCompareBitFile;
835         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 8;
836         EXPECT_JSON_INVALID(configFile, "Validation failed.",
837                             "8 is greater than the maximum of 7");
838     }
839     // Invalid: test i2c_compare_bit with position less than 0.
840     {
841         json configFile = i2cCompareBitFile;
842         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
843             -1;
844         EXPECT_JSON_INVALID(configFile, "Validation failed.",
845                             "-1 is less than the minimum of 0");
846     }
847     // Invalid: test i2c_compare_bit with value wrong type.
848     {
849         json configFile = i2cCompareBitFile;
850         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = "1";
851         EXPECT_JSON_INVALID(configFile, "Validation failed.",
852                             "'1' is not of type 'integer'");
853     }
854     // Invalid: test i2c_compare_bit with value greater than 1.
855     {
856         json configFile = i2cCompareBitFile;
857         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 2;
858         EXPECT_JSON_INVALID(configFile, "Validation failed.",
859                             "2 is greater than the maximum of 1");
860     }
861     // Invalid: test i2c_compare_bit with value less than 0.
862     {
863         json configFile = i2cCompareBitFile;
864         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = -1;
865         EXPECT_JSON_INVALID(configFile, "Validation failed.",
866                             "-1 is less than the minimum of 0");
867     }
868 }
869 TEST(ValidateRegulatorsConfigTest, I2CCompareByte)
870 {
871     json i2cCompareByteFile = validConfigFile;
872     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]
873                       ["register"] = "0x82";
874     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
875         "0x40";
876     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
877         "0x7F";
878     // Valid: test i2c_compare_byte with all properties.
879     {
880         json configFile = i2cCompareByteFile;
881         EXPECT_JSON_VALID(configFile);
882     }
883     // Valid: test i2c_compare_byte with all required properties.
884     {
885         json configFile = i2cCompareByteFile;
886         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("mask");
887         EXPECT_JSON_VALID(configFile);
888     }
889     // Invalid: test i2c_compare_byte with no register.
890     {
891         json configFile = i2cCompareByteFile;
892         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase(
893             "register");
894         EXPECT_JSON_INVALID(configFile, "Validation failed.",
895                             "'register' is a required property");
896     }
897     // Invalid: test i2c_compare_byte with no value.
898     {
899         json configFile = i2cCompareByteFile;
900         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("value");
901         EXPECT_JSON_INVALID(configFile, "Validation failed.",
902                             "'value' is a required property");
903     }
904     // Invalid: test i2c_compare_byte with property register wrong type.
905     {
906         json configFile = i2cCompareByteFile;
907         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
908             1;
909         EXPECT_JSON_INVALID(configFile, "Validation failed.",
910                             "1 is not of type 'string'");
911     }
912     // Invalid: test i2c_compare_byte with property value wrong type.
913     {
914         json configFile = i2cCompareByteFile;
915         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] = 1;
916         EXPECT_JSON_INVALID(configFile, "Validation failed.",
917                             "1 is not of type 'string'");
918     }
919     // Invalid: test i2c_compare_byte with property mask wrong type.
920     {
921         json configFile = i2cCompareByteFile;
922         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = 1;
923         EXPECT_JSON_INVALID(configFile, "Validation failed.",
924                             "1 is not of type 'string'");
925     }
926     // Invalid: test i2c_compare_byte with property register more than 2 hex
927     // digits.
928     {
929         json configFile = i2cCompareByteFile;
930         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
931             "0x820";
932         EXPECT_JSON_INVALID(configFile, "Validation failed.",
933                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
934     }
935     // Invalid: test i2c_compare_byte with property value more than 2 hex
936     // digits.
937     {
938         json configFile = i2cCompareByteFile;
939         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
940             "0x820";
941         EXPECT_JSON_INVALID(configFile, "Validation failed.",
942                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
943     }
944     // Invalid: test i2c_compare_byte with property mask more than 2 hex digits.
945     {
946         json configFile = i2cCompareByteFile;
947         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
948             "0x820";
949         EXPECT_JSON_INVALID(configFile, "Validation failed.",
950                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
951     }
952     // Invalid: test i2c_compare_byte with property register less than 2 hex
953     // digits.
954     {
955         json configFile = i2cCompareByteFile;
956         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
957             "0x8";
958         EXPECT_JSON_INVALID(configFile, "Validation failed.",
959                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
960     }
961     // Invalid: test i2c_compare_byte with property value less than 2 hex
962     // digits.
963     {
964         json configFile = i2cCompareByteFile;
965         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
966             "0x8";
967         EXPECT_JSON_INVALID(configFile, "Validation failed.",
968                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
969     }
970     // Invalid: test i2c_compare_byte with property mask less than 2 hex digits.
971     {
972         json configFile = i2cCompareByteFile;
973         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
974             "0x8";
975         EXPECT_JSON_INVALID(configFile, "Validation failed.",
976                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
977     }
978     // Invalid: test i2c_compare_byte with property register no leading prefix.
979     {
980         json configFile = i2cCompareByteFile;
981         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
982             "82";
983         EXPECT_JSON_INVALID(configFile, "Validation failed.",
984                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
985     }
986     // Invalid: test i2c_compare_byte with property value no leading prefix.
987     {
988         json configFile = i2cCompareByteFile;
989         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
990             "82";
991         EXPECT_JSON_INVALID(configFile, "Validation failed.",
992                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
993     }
994     // Invalid: test i2c_compare_byte with property mask no leading prefix.
995     {
996         json configFile = i2cCompareByteFile;
997         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = "82";
998         EXPECT_JSON_INVALID(configFile, "Validation failed.",
999                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1000     }
1001     // Invalid: test i2c_compare_byte with property register invalid hex digit.
1002     {
1003         json configFile = i2cCompareByteFile;
1004         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1005             "0xG1";
1006         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1007                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1008     }
1009     // Invalid: test i2c_compare_byte with property value invalid hex digit.
1010     {
1011         json configFile = i2cCompareByteFile;
1012         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1013             "0xG1";
1014         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1015                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1016     }
1017     // Invalid: test i2c_compare_byte with property mask invalid hex digit.
1018     {
1019         json configFile = i2cCompareByteFile;
1020         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1021             "0xG1";
1022         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1023                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1024     }
1025 }
1026 TEST(ValidateRegulatorsConfigTest, I2CCompareBytes)
1027 {
1028     json i2cCompareBytesFile = validConfigFile;
1029     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1030                        ["register"] = "0x82";
1031     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1032                        ["values"] = {"0x02", "0x73"};
1033     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1034                        ["masks"] = {"0x7F", "0x7F"};
1035     // Valid: test i2c_compare_bytes.
1036     {
1037         json configFile = i2cCompareBytesFile;
1038         EXPECT_JSON_VALID(configFile);
1039     }
1040     // Valid: test i2c_compare_bytes with all required properties.
1041     {
1042         json configFile = i2cCompareBytesFile;
1043         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1044             "masks");
1045         EXPECT_JSON_VALID(configFile);
1046     }
1047     // Invalid: test i2c_compare_bytes with no register.
1048     {
1049         json configFile = i2cCompareBytesFile;
1050         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1051             "register");
1052         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1053                             "'register' is a required property");
1054     }
1055     // Invalid: test i2c_compare_bytes with no values.
1056     {
1057         json configFile = i2cCompareBytesFile;
1058         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1059             "values");
1060         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1061                             "'values' is a required property");
1062     }
1063     // Invalid: test i2c_compare_bytes with property values as empty array.
1064     {
1065         json configFile = i2cCompareBytesFile;
1066         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] =
1067             json::array();
1068         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1069                             "[] is too short");
1070     }
1071     // Invalid: test i2c_compare_bytes with property masks as empty array.
1072     {
1073         json configFile = i2cCompareBytesFile;
1074         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] =
1075             json::array();
1076         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1077                             "[] is too short");
1078     }
1079     // Invalid: test i2c_compare_bytes with property register wrong type.
1080     {
1081         json configFile = i2cCompareBytesFile;
1082         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1083             1;
1084         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1085                             "1 is not of type 'string'");
1086     }
1087     // Invalid: test i2c_compare_bytes with property values wrong type.
1088     {
1089         json configFile = i2cCompareBytesFile;
1090         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = 1;
1091         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1092                             "1 is not of type 'array'");
1093     }
1094     // Invalid: test i2c_compare_bytes with property masks wrong type.
1095     {
1096         json configFile = i2cCompareBytesFile;
1097         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = 1;
1098         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1099                             "1 is not of type 'array'");
1100     }
1101     // Invalid: test i2c_compare_bytes with property register more than 2 hex
1102     // digits.
1103     {
1104         json configFile = i2cCompareBytesFile;
1105         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1106             "0x820";
1107         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1108                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1109     }
1110     // Invalid: test i2c_compare_bytes with property values more than 2 hex
1111     // digits.
1112     {
1113         json configFile = i2cCompareBytesFile;
1114         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1115             "0x820";
1116         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1117                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1118     }
1119     // Invalid: test i2c_compare_bytes with property masks more than 2 hex
1120     // digits.
1121     {
1122         json configFile = i2cCompareBytesFile;
1123         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1124             "0x820";
1125         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1126                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1127     }
1128     // Invalid: test i2c_compare_bytes with property register less than 2 hex
1129     // digits.
1130     {
1131         json configFile = i2cCompareBytesFile;
1132         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1133             "0x8";
1134         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1135                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1136     }
1137     // Invalid: test i2c_compare_bytes with property values less than 2 hex
1138     // digits.
1139     {
1140         json configFile = i2cCompareBytesFile;
1141         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1142             "0x8";
1143         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1144                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1145     }
1146     // Invalid: test i2c_compare_bytes with property masks less than 2 hex
1147     // digits.
1148     {
1149         json configFile = i2cCompareBytesFile;
1150         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1151             "0x8";
1152         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1153                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1154     }
1155     // Invalid: test i2c_compare_bytes with property register no leading prefix.
1156     {
1157         json configFile = i2cCompareBytesFile;
1158         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1159             "82";
1160         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1161                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1162     }
1163     // Invalid: test i2c_compare_bytes with property values no leading prefix.
1164     {
1165         json configFile = i2cCompareBytesFile;
1166         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1167             "82";
1168         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1169                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1170     }
1171     // Invalid: test i2c_compare_bytes with property masks no leading prefix.
1172     {
1173         json configFile = i2cCompareBytesFile;
1174         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1175             "82";
1176         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1177                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1178     }
1179     // Invalid: test i2c_compare_bytes with property register invalid hex digit.
1180     {
1181         json configFile = i2cCompareBytesFile;
1182         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1183             "0xG1";
1184         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1185                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1186     }
1187     // Invalid: test i2c_compare_bytes with property values invalid hex digit.
1188     {
1189         json configFile = i2cCompareBytesFile;
1190         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1191             "0xG1";
1192         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1193                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1194     }
1195     // Invalid: test i2c_compare_bytes with property masks invalid hex digit.
1196     {
1197         json configFile = i2cCompareBytesFile;
1198         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1199             "0xG1";
1200         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1201                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1202     }
1203 }
1204 TEST(ValidateRegulatorsConfigTest, I2CInterface)
1205 {
1206     // Valid: test i2c_interface.
1207     {
1208         json configFile = validConfigFile;
1209         EXPECT_JSON_VALID(configFile);
1210     }
1211     // Invalid: testi2c_interface with no bus.
1212     {
1213         json configFile = validConfigFile;
1214         configFile["chassis"][0]["devices"][0]["i2c_interface"].erase("bus");
1215         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1216                             "'bus' is a required property");
1217     }
1218     // Invalid: test i2c_interface with no address.
1219     {
1220         json configFile = validConfigFile;
1221         configFile["chassis"][0]["devices"][0]["i2c_interface"].erase(
1222             "address");
1223         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1224                             "'address' is a required property");
1225     }
1226     // Invalid: test i2c_interface with property bus wrong type.
1227     {
1228         json configFile = validConfigFile;
1229         configFile["chassis"][0]["devices"][0]["i2c_interface"]["bus"] = true;
1230         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1231                             "True is not of type 'integer'");
1232     }
1233     // Invalid: test i2c_interface with property address wrong
1234     // type.
1235     {
1236         json configFile = validConfigFile;
1237         configFile["chassis"][0]["devices"][0]["i2c_interface"]["address"] =
1238             true;
1239         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1240                             "True is not of type 'string'");
1241     }
1242     // Invalid: test i2c_interface with property bus less than
1243     // 0.
1244     {
1245         json configFile = validConfigFile;
1246         configFile["chassis"][0]["devices"][0]["i2c_interface"]["bus"] = -1;
1247         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1248                             "-1 is less than the minimum of 0");
1249     }
1250     // Invalid: test i2c_interface with property address wrong
1251     // format.
1252     {
1253         json configFile = validConfigFile;
1254         configFile["chassis"][0]["devices"][0]["i2c_interface"]["address"] =
1255             "0x700";
1256         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1257                             "'0x700' does not match '^0x[0-9A-Fa-f]{2}$'");
1258     }
1259 }
1260 TEST(ValidateRegulatorsConfigTest, I2CWriteBit)
1261 {
1262     json i2cWriteBitFile = validConfigFile;
1263     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
1264         "0xA0";
1265     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3;
1266     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 1;
1267     // Valid: test rule actions i2c_write_bit.
1268     {
1269         json configFile = i2cWriteBitFile;
1270         EXPECT_JSON_VALID(configFile);
1271     }
1272     // Invalid: test i2c_write_bit with no register.
1273     {
1274         json configFile = i2cWriteBitFile;
1275         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("register");
1276         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1277                             "'register' is a required property");
1278     }
1279     // Invalid: test i2c_write_bit with no position.
1280     {
1281         json configFile = i2cWriteBitFile;
1282         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("position");
1283         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1284                             "'position' is a required property");
1285     }
1286     // Invalid: test i2c_write_bit with no value.
1287     {
1288         json configFile = i2cWriteBitFile;
1289         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("value");
1290         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1291                             "'value' is a required property");
1292     }
1293     // Invalid: test i2c_write_bit with register wrong type.
1294     {
1295         json configFile = i2cWriteBitFile;
1296         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] = 1;
1297         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1298                             "1 is not of type 'string'");
1299     }
1300     // Invalid: test i2c_write_bit with register wrong format.
1301     {
1302         json configFile = i2cWriteBitFile;
1303         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
1304             "0xA00";
1305         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1306                             "'0xA00' does not match '^0x[0-9A-Fa-f]{2}$'");
1307     }
1308     // Invalid: test i2c_write_bit with position wrong type.
1309     {
1310         json configFile = i2cWriteBitFile;
1311         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3.1;
1312         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1313                             "3.1 is not of type 'integer'");
1314     }
1315     // Invalid: test i2c_write_bit with position greater than 7.
1316     {
1317         json configFile = i2cWriteBitFile;
1318         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 8;
1319         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1320                             "8 is greater than the maximum of 7");
1321     }
1322     // Invalid: test i2c_write_bit with position less than 0.
1323     {
1324         json configFile = i2cWriteBitFile;
1325         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = -1;
1326         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1327                             "-1 is less than the minimum of 0");
1328     }
1329     // Invalid: test i2c_write_bit with value wrong type.
1330     {
1331         json configFile = i2cWriteBitFile;
1332         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = "1";
1333         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1334                             "'1' is not of type 'integer'");
1335     }
1336     // Invalid: test i2c_write_bit with value greater than 1.
1337     {
1338         json configFile = i2cWriteBitFile;
1339         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 2;
1340         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1341                             "2 is greater than the maximum of 1");
1342     }
1343     // Invalid: test i2c_write_bit with value less than 0.
1344     {
1345         json configFile = i2cWriteBitFile;
1346         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = -1;
1347         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1348                             "-1 is less than the minimum of 0");
1349     }
1350 }
1351 TEST(ValidateRegulatorsConfigTest, I2CWriteByte)
1352 {
1353     json i2cWriteByteFile = validConfigFile;
1354     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1355         "0x82";
1356     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1357         "0x40";
1358     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] =
1359         "0x7F";
1360     // Valid: test i2c_write_byte with all properties.
1361     {
1362         json configFile = i2cWriteByteFile;
1363         EXPECT_JSON_VALID(configFile);
1364     }
1365     // Valid: test i2c_write_byte with all required properties.
1366     {
1367         json configFile = i2cWriteByteFile;
1368         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase("mask");
1369         EXPECT_JSON_VALID(configFile);
1370     }
1371     // Invalid: test i2c_write_byte with no register.
1372     {
1373         json configFile = i2cWriteByteFile;
1374         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase(
1375             "register");
1376         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1377                             "'register' is a required property");
1378     }
1379     // Invalid: test i2c_write_byte with no value.
1380     {
1381         json configFile = i2cWriteByteFile;
1382         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase("value");
1383         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1384                             "'value' is a required property");
1385     }
1386     // Invalid: test i2c_write_byte with property register wrong type.
1387     {
1388         json configFile = i2cWriteByteFile;
1389         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] = 1;
1390         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1391                             "1 is not of type 'string'");
1392     }
1393     // Invalid: test i2c_write_byte with property value wrong type.
1394     {
1395         json configFile = i2cWriteByteFile;
1396         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = 1;
1397         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1398                             "1 is not of type 'string'");
1399     }
1400     // Invalid: test i2c_write_byte with property mask wrong type.
1401     {
1402         json configFile = i2cWriteByteFile;
1403         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = 1;
1404         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1405                             "1 is not of type 'string'");
1406     }
1407     // Invalid: test i2c_write_byte with property register more than 2 hex
1408     // digits.
1409     {
1410         json configFile = i2cWriteByteFile;
1411         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1412             "0x820";
1413         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1414                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1415     }
1416     // Invalid: test i2c_write_byte with property value more than 2 hex
1417     // digits.
1418     {
1419         json configFile = i2cWriteByteFile;
1420         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1421             "0x820";
1422         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1423                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1424     }
1425     // Invalid: test i2c_write_byte with property mask more than 2 hex digits.
1426     {
1427         json configFile = i2cWriteByteFile;
1428         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] =
1429             "0x820";
1430         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1431                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1432     }
1433     // Invalid: test i2c_write_byte with property register less than 2 hex
1434     // digits.
1435     {
1436         json configFile = i2cWriteByteFile;
1437         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1438             "0x8";
1439         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1440                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1441     }
1442     // Invalid: test i2c_write_byte with property value less than 2 hex
1443     // digits.
1444     {
1445         json configFile = i2cWriteByteFile;
1446         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = "0x8";
1447         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1448                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1449     }
1450     // Invalid: test i2c_write_byte with property mask less than 2 hex digits.
1451     {
1452         json configFile = i2cWriteByteFile;
1453         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0x8";
1454         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1455                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1456     }
1457     // Invalid: test i2c_write_byte with property register no leading prefix.
1458     {
1459         json configFile = i2cWriteByteFile;
1460         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1461             "82";
1462         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1463                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1464     }
1465     // Invalid: test i2c_write_byte with property value no leading prefix.
1466     {
1467         json configFile = i2cWriteByteFile;
1468         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = "82";
1469         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1470                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1471     }
1472     // Invalid: test i2c_write_byte with property mask no leading prefix.
1473     {
1474         json configFile = i2cWriteByteFile;
1475         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "82";
1476         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1477                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1478     }
1479     // Invalid: test i2c_write_byte with property register invalid hex digit.
1480     {
1481         json configFile = i2cWriteByteFile;
1482         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1483             "0xG1";
1484         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1485                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1486     }
1487     // Invalid: test i2c_write_byte with property value invalid hex digit.
1488     {
1489         json configFile = i2cWriteByteFile;
1490         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1491             "0xG1";
1492         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1493                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1494     }
1495     // Invalid: test i2c_write_byte with property mask invalid hex digit.
1496     {
1497         json configFile = i2cWriteByteFile;
1498         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0xG1";
1499         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1500                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1501     }
1502 }
1503 TEST(ValidateRegulatorsConfigTest, I2CWriteBytes)
1504 {
1505     json i2cWriteBytesFile = validConfigFile;
1506     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1507         "0x82";
1508     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
1509         "0x02", "0x73"};
1510     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
1511         "0x7F", "0x7F"};
1512     // Valid: test i2c_write_bytes.
1513     {
1514         json configFile = i2cWriteBytesFile;
1515         EXPECT_JSON_VALID(configFile);
1516     }
1517     // Valid: test i2c_write_bytes with all required properties.
1518     {
1519         json configFile = i2cWriteBytesFile;
1520         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase("masks");
1521         EXPECT_JSON_VALID(configFile);
1522     }
1523     // Invalid: test i2c_write_bytes with no register.
1524     {
1525         json configFile = i2cWriteBytesFile;
1526         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase(
1527             "register");
1528         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1529                             "'register' is a required property");
1530     }
1531     // Invalid: test i2c_write_bytes with no values.
1532     {
1533         json configFile = i2cWriteBytesFile;
1534         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase("values");
1535         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1536                             "'values' is a required property");
1537     }
1538     // Invalid: test i2c_write_bytes with property values as empty array.
1539     {
1540         json configFile = i2cWriteBytesFile;
1541         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] =
1542             json::array();
1543         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1544                             "[] is too short");
1545     }
1546     // Invalid: test i2c_write_bytes with property masks as empty array.
1547     {
1548         json configFile = i2cWriteBytesFile;
1549         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] =
1550             json::array();
1551         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1552                             "[] is too short");
1553     }
1554     // Invalid: test i2c_write_bytes with property register wrong type.
1555     {
1556         json configFile = i2cWriteBytesFile;
1557         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] = 1;
1558         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1559                             "1 is not of type 'string'");
1560     }
1561     // Invalid: test i2c_write_bytes with property values wrong type.
1562     {
1563         json configFile = i2cWriteBytesFile;
1564         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = 1;
1565         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1566                             "1 is not of type 'array'");
1567     }
1568     // Invalid: test i2c_write_bytes with property masks wrong type.
1569     {
1570         json configFile = i2cWriteBytesFile;
1571         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = 1;
1572         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1573                             "1 is not of type 'array'");
1574     }
1575     // Invalid: test i2c_write_bytes with property register more than 2 hex
1576     // digits.
1577     {
1578         json configFile = i2cWriteBytesFile;
1579         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1580             "0x820";
1581         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1582                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1583     }
1584     // Invalid: test i2c_write_bytes with property values more than 2 hex
1585     // digits.
1586     {
1587         json configFile = i2cWriteBytesFile;
1588         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1589             "0x820";
1590         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1591                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1592     }
1593     // Invalid: test i2c_write_bytes with property masks more than 2 hex
1594     // digits.
1595     {
1596         json configFile = i2cWriteBytesFile;
1597         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1598             "0x820";
1599         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1600                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1601     }
1602     // Invalid: test i2c_write_bytes with property register less than 2 hex
1603     // digits.
1604     {
1605         json configFile = i2cWriteBytesFile;
1606         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1607             "0x8";
1608         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1609                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1610     }
1611     // Invalid: test i2c_write_bytes with property values less than 2 hex
1612     // digits.
1613     {
1614         json configFile = i2cWriteBytesFile;
1615         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1616             "0x8";
1617         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1618                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1619     }
1620     // Invalid: test i2c_write_bytes with property masks less than 2 hex
1621     // digits.
1622     {
1623         json configFile = i2cWriteBytesFile;
1624         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1625             "0x8";
1626         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1627                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1628     }
1629     // Invalid: test i2c_write_bytes with property register no leading prefix.
1630     {
1631         json configFile = i2cWriteBytesFile;
1632         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1633             "82";
1634         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1635                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1636     }
1637     // Invalid: test i2c_write_bytes with property values no leading prefix.
1638     {
1639         json configFile = i2cWriteBytesFile;
1640         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1641             "82";
1642         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1643                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1644     }
1645     // Invalid: test i2c_write_bytes with property masks no leading prefix.
1646     {
1647         json configFile = i2cWriteBytesFile;
1648         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1649             "82";
1650         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1651                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1652     }
1653     // Invalid: test i2c_write_bytes with property register invalid hex digit.
1654     {
1655         json configFile = i2cWriteBytesFile;
1656         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1657             "0xG1";
1658         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1659                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1660     }
1661     // Invalid: test i2c_write_bytes with property values invalid hex digit.
1662     {
1663         json configFile = i2cWriteBytesFile;
1664         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1665             "0xG1";
1666         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1667                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1668     }
1669     // Invalid: test i2c_write_bytes with property masks invalid hex digit.
1670     {
1671         json configFile = i2cWriteBytesFile;
1672         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1673             "0xG1";
1674         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1675                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1676     }
1677 }
1678 TEST(ValidateRegulatorsConfigTest, If)
1679 {
1680     json ifFile = validConfigFile;
1681     ifFile["rules"][2]["actions"][0]["if"]["condition"]["run_rule"] =
1682         "set_voltage_rule";
1683     ifFile["rules"][2]["actions"][0]["if"]["then"][0]["run_rule"] =
1684         "read_sensors_rule";
1685     ifFile["rules"][2]["actions"][0]["if"]["else"][0]["run_rule"] =
1686         "read_sensors_rule";
1687     ifFile["rules"][2]["id"] = "rule_if";
1688     // Valid: test if.
1689     {
1690         json configFile = ifFile;
1691         EXPECT_JSON_VALID(configFile);
1692     }
1693     // Valid: test if with required properties.
1694     {
1695         json configFile = ifFile;
1696         configFile["rules"][2]["actions"][0]["if"].erase("else");
1697         EXPECT_JSON_VALID(configFile);
1698     }
1699     // Invalid: test if with no property condition.
1700     {
1701         json configFile = ifFile;
1702         configFile["rules"][2]["actions"][0]["if"].erase("condition");
1703         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1704                             "'condition' is a required property");
1705     }
1706     // Invalid: test if with no property then.
1707     {
1708         json configFile = ifFile;
1709         configFile["rules"][2]["actions"][0]["if"].erase("then");
1710         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1711                             "'then' is a required property");
1712     }
1713     // Invalid: test if with property then empty array.
1714     {
1715         json configFile = ifFile;
1716         configFile["rules"][2]["actions"][0]["if"]["then"] = json::array();
1717         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1718                             "[] is too short");
1719     }
1720     // Invalid: test if with property else empty array.
1721     {
1722         json configFile = ifFile;
1723         configFile["rules"][2]["actions"][0]["if"]["else"] = json::array();
1724         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1725                             "[] is too short");
1726     }
1727     // Invalid: test if with property condition wrong type.
1728     {
1729         json configFile = ifFile;
1730         configFile["rules"][2]["actions"][0]["if"]["condition"] = 1;
1731         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1732                             "1 is not of type 'object'");
1733     }
1734     // Invalid: test if with property then wrong type.
1735     {
1736         json configFile = ifFile;
1737         configFile["rules"][2]["actions"][0]["if"]["then"] = 1;
1738         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1739                             "1 is not of type 'array'");
1740     }
1741     // Invalid: test if with property else wrong type.
1742     {
1743         json configFile = ifFile;
1744         configFile["rules"][2]["actions"][0]["if"]["else"] = 1;
1745         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1746                             "1 is not of type 'array'");
1747     }
1748 }
1749 TEST(ValidateRegulatorsConfigTest, Not)
1750 {
1751     json notFile = validConfigFile;
1752     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["register"] =
1753         "0xA0";
1754     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["value"] =
1755         "0xFF";
1756     // Valid: test not.
1757     {
1758         json configFile = notFile;
1759         EXPECT_JSON_VALID(configFile);
1760     }
1761     // Invalid: test not with wrong type.
1762     {
1763         json configFile = notFile;
1764         configFile["rules"][0]["actions"][1]["not"] = 1;
1765         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1766                             "1 is not of type 'object'");
1767     }
1768 }
1769 TEST(ValidateRegulatorsConfigTest, Or)
1770 {
1771     json orFile = validConfigFile;
1772     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["register"] =
1773         "0xA0";
1774     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["value"] =
1775         "0x00";
1776     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["register"] =
1777         "0xA1";
1778     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["value"] =
1779         "0x00";
1780     // Valid: test or.
1781     {
1782         json configFile = orFile;
1783         EXPECT_JSON_VALID(configFile);
1784     }
1785     // Invalid: test or with empty array.
1786     {
1787         json configFile = orFile;
1788         configFile["rules"][0]["actions"][1]["or"] = json::array();
1789         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1790                             "[] is too short");
1791     }
1792     // Invalid: test or with wrong type.
1793     {
1794         json configFile = orFile;
1795         configFile["rules"][0]["actions"][1]["or"] = 1;
1796         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1797                             "1 is not of type 'array'");
1798     }
1799 }
1800 TEST(ValidateRegulatorsConfigTest, PmbusReadSensor)
1801 {
1802     json pmbusReadSensorFile = validConfigFile;
1803     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1804         "vout";
1805     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1806                        ["command"] = "0x8B";
1807     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1808                        ["format"] = "linear_16";
1809     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1810                        ["exponent"] = -8;
1811     // Valid: test pmbus_read_sensor.
1812     {
1813         json configFile = pmbusReadSensorFile;
1814         EXPECT_JSON_VALID(configFile);
1815     }
1816     // Valid: test pmbus_read_sensor with required properties.
1817     {
1818         json configFile = pmbusReadSensorFile;
1819         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1820             "exponent");
1821         EXPECT_JSON_VALID(configFile);
1822     }
1823     // Invalid: test pmbus_read_sensor with no type.
1824     {
1825         json configFile = pmbusReadSensorFile;
1826         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase("type");
1827         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1828                             "'type' is a required property");
1829     }
1830     // Invalid: test pmbus_read_sensor with no command.
1831     {
1832         json configFile = pmbusReadSensorFile;
1833         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1834             "command");
1835         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1836                             "'command' is a required property");
1837     }
1838     // Invalid: test pmbus_read_sensor with no format.
1839     {
1840         json configFile = pmbusReadSensorFile;
1841         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1842             "format");
1843         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1844                             "'format' is a required property");
1845     }
1846     // Invalid: test pmbus_read_sensor with property type wrong type.
1847     {
1848         json configFile = pmbusReadSensorFile;
1849         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1850             true;
1851         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1852                             "True is not of type 'string'");
1853     }
1854     // Invalid: test pmbus_read_sensor with property command wrong type.
1855     {
1856         json configFile = pmbusReadSensorFile;
1857         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1858             true;
1859         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1860                             "True is not of type 'string'");
1861     }
1862     // Invalid: test pmbus_read_sensor with property format wrong type.
1863     {
1864         json configFile = pmbusReadSensorFile;
1865         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1866             true;
1867         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1868                             "True is not of type 'string'");
1869     }
1870     // Invalid: test pmbus_read_sensor with property exponent wrong type.
1871     {
1872         json configFile = pmbusReadSensorFile;
1873         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["exponent"] =
1874             true;
1875         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1876                             "True is not of type 'integer'");
1877     }
1878     // Invalid: test pmbus_read_sensor with property type wrong format.
1879     {
1880         json configFile = pmbusReadSensorFile;
1881         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1882             "foo";
1883         EXPECT_JSON_INVALID(
1884             configFile, "Validation failed.",
1885             "'foo' is not one of ['iout', 'iout_peak', 'iout_valley', "
1886             "'pout', 'temperature', 'temperature_peak', 'vout', "
1887             "'vout_peak', 'vout_valley']");
1888     }
1889     // Invalid: test pmbus_read_sensor with property command wrong format.
1890     {
1891         json configFile = pmbusReadSensorFile;
1892         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1893             "0x8B0";
1894         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1895                             "'0x8B0' does not match '^0x[0-9a-fA-F]{2}$'");
1896     }
1897     // Invalid: test pmbus_read_sensor with property format wrong format.
1898     {
1899         json configFile = pmbusReadSensorFile;
1900         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1901             "foo";
1902         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1903                             "'foo' is not one of ['linear_11', 'linear_16']");
1904     }
1905 }
1906 TEST(ValidateRegulatorsConfigTest, PmbusWriteVoutCommand)
1907 {
1908     json pmbusWriteVoutCommandFile = validConfigFile;
1909     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1910                              ["pmbus_write_vout_command"]["volts"] = 1.03;
1911     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1912                              ["pmbus_write_vout_command"]["format"] = "linear";
1913     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1914                              ["pmbus_write_vout_command"]["exponent"] = -8;
1915     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1916                              ["pmbus_write_vout_command"]["is_verified"] = true;
1917     // Valid: test pmbus_write_vout_command.
1918     {
1919         json configFile = pmbusWriteVoutCommandFile;
1920         EXPECT_JSON_VALID(configFile);
1921     }
1922     // Valid: test pmbus_write_vout_command with required properties.
1923     {
1924         json configFile = pmbusWriteVoutCommandFile;
1925         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1926             "volts");
1927         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1928             "exponent");
1929         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1930             "is_verified");
1931         EXPECT_JSON_VALID(configFile);
1932     }
1933     // Invalid: test pmbus_write_vout_command with no format.
1934     {
1935         json configFile = pmbusWriteVoutCommandFile;
1936         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1937             "format");
1938         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1939                             "'format' is a required property");
1940     }
1941     // Invalid: test pmbus_write_vout_command with property volts wrong type.
1942     {
1943         json configFile = pmbusWriteVoutCommandFile;
1944         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1945                   ["volts"] = true;
1946         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1947                             "True is not of type 'number'");
1948     }
1949     // Invalid: test pmbus_write_vout_command with property format wrong type.
1950     {
1951         json configFile = pmbusWriteVoutCommandFile;
1952         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1953                   ["format"] = true;
1954         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1955                             "True is not of type 'string'");
1956     }
1957     // Invalid: test pmbus_write_vout_command with property exponent wrong type.
1958     {
1959         json configFile = pmbusWriteVoutCommandFile;
1960         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1961                   ["exponent"] = 1.3;
1962         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1963                             "1.3 is not of type 'integer'");
1964     }
1965     // Invalid: test pmbus_write_vout_command with property is_verified wrong
1966     // type.
1967     {
1968         json configFile = pmbusWriteVoutCommandFile;
1969         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1970                   ["is_verified"] = 1;
1971         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1972                             "1 is not of type 'boolean'");
1973     }
1974     // Invalid: test pmbus_write_vout_command with property format wrong format.
1975     {
1976         json configFile = pmbusWriteVoutCommandFile;
1977         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1978                   ["format"] = "foo";
1979         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1980                             "'foo' is not one of ['linear']");
1981     }
1982 }
1983 TEST(ValidateRegulatorsConfigTest, PresenceDetection)
1984 {
1985     json presenceDetectionFile = validConfigFile;
1986     presenceDetectionFile
1987         ["chassis"][0]["devices"][0]["presence_detection"]["comments"][0] =
1988             "Regulator is only present on the FooBar backplane";
1989     presenceDetectionFile["chassis"][0]["devices"][0]["presence_detection"]
1990                          ["rule_id"] = "set_voltage_rule";
1991     // Valid: test presence_detection with only property rule_id.
1992     {
1993         json configFile = presenceDetectionFile;
1994         EXPECT_JSON_VALID(configFile);
1995     }
1996     // Valid: test presence_detection with only property actions.
1997     {
1998         json configFile = presenceDetectionFile;
1999         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2000             "rule_id");
2001         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2002                   [0]["compare_presence"]["fru"] =
2003                       "/system/chassis/motherboard/cpu3";
2004         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2005                   [0]["compare_presence"]["value"] = true;
2006         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2007             "comments");
2008         EXPECT_JSON_VALID(configFile);
2009     }
2010     // Invalid: test presence_detection with both property rule_id and actions.
2011     {
2012         json configFile = presenceDetectionFile;
2013         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2014                   [0]["compare_presence"]["fru"] =
2015                       "/system/chassis/motherboard/cpu3";
2016         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2017                   [0]["compare_presence"]["value"] = true;
2018         EXPECT_JSON_INVALID(
2019             configFile, "Validation failed.",
2020             "{'actions': [{'compare_presence': {'fru': "
2021             "'/system/chassis/motherboard/cpu3', 'value': True}}], 'comments': "
2022             "['Regulator is only present on the FooBar backplane'], 'rule_id': "
2023             "'set_voltage_rule'} is valid under each of {'required': "
2024             "['actions']}, {'required': ['rule_id']}");
2025     }
2026     // Invalid: test presence_detection with no rule_id and actions.
2027     {
2028         json configFile = presenceDetectionFile;
2029         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2030             "rule_id");
2031         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2032                             "'rule_id' is a required property");
2033     }
2034     // Invalid: test presence_detection with property comments wrong type.
2035     {
2036         json configFile = presenceDetectionFile;
2037         configFile["chassis"][0]["devices"][0]["presence_detection"]
2038                   ["comments"] = true;
2039         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2040                             "True is not of type 'array'");
2041     }
2042     // Invalid: test presence_detection with property rule_id wrong type.
2043     {
2044         json configFile = presenceDetectionFile;
2045         configFile["chassis"][0]["devices"][0]["presence_detection"]
2046                   ["rule_id"] = true;
2047         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2048                             "True is not of type 'string'");
2049     }
2050     // Invalid: test presence_detection with property actions wrong type.
2051     {
2052         json configFile = presenceDetectionFile;
2053         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2054             "rule_id");
2055         configFile["chassis"][0]["devices"][0]["presence_detection"]
2056                   ["actions"] = true;
2057         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2058                             "True is not of type 'array'");
2059     }
2060     // Invalid: test presence_detection with property rule_id wrong format.
2061     {
2062         json configFile = presenceDetectionFile;
2063         configFile["chassis"][0]["devices"][0]["presence_detection"]
2064                   ["rule_id"] = "id@";
2065         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2066                             "'id@' does not match '^[A-Za-z0-9_]+$'");
2067     }
2068     // Invalid: test presence_detection with property comments empty array.
2069     {
2070         json configFile = presenceDetectionFile;
2071         configFile["chassis"][0]["devices"][0]["presence_detection"]
2072                   ["comments"] = json::array();
2073         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2074                             "[] is too short");
2075     }
2076     // Invalid: test presence_detection with property actions empty array.
2077     {
2078         json configFile = presenceDetectionFile;
2079         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2080             "rule_id");
2081         configFile["chassis"][0]["devices"][0]["presence_detection"]
2082                   ["actions"] = json::array();
2083         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2084                             "[] is too short");
2085     }
2086 }
2087 TEST(ValidateRegulatorsConfigTest, Rail)
2088 {
2089     // Valid: test rail.
2090     {
2091         json configFile = validConfigFile;
2092         EXPECT_JSON_VALID(configFile);
2093     }
2094     // Valid: test rail with required properties.
2095     {
2096         json configFile = validConfigFile;
2097         configFile["chassis"][0]["devices"][0]["rails"][0].erase("comments");
2098         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2099             "configuration");
2100         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2101             "sensor_monitoring");
2102         EXPECT_JSON_VALID(configFile);
2103     }
2104     // Invalid: test rail with no id.
2105     {
2106         json configFile = validConfigFile;
2107         configFile["chassis"][0]["devices"][0]["rails"][0].erase("id");
2108         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2109                             "'id' is a required property");
2110     }
2111     // Invalid: test rail with comments wrong type.
2112     {
2113         json configFile = validConfigFile;
2114         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] = true;
2115         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2116                             "True is not of type 'array'");
2117     }
2118     // Invalid: test rail with id wrong type.
2119     {
2120         json configFile = validConfigFile;
2121         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = true;
2122         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2123                             "True is not of type 'string'");
2124     }
2125     // Invalid: test rail with configuration wrong type.
2126     {
2127         json configFile = validConfigFile;
2128         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"] =
2129             true;
2130         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2131                             "True is not of type 'object'");
2132     }
2133     // Invalid: test rail with sensor_monitoring wrong type.
2134     {
2135         json configFile = validConfigFile;
2136         configFile["chassis"][0]["devices"][0]["rails"][0]
2137                   ["sensor_monitoring"] = true;
2138         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2139                             "True is not of type 'object'");
2140     }
2141     // Invalid: test rail with comments empty array.
2142     {
2143         json configFile = validConfigFile;
2144         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] =
2145             json::array();
2146         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2147                             "[] is too short");
2148     }
2149     // Invalid: test rail with id wrong format.
2150     {
2151         json configFile = validConfigFile;
2152         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = "id~";
2153         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2154                             "'id~' does not match '^[A-Za-z0-9_]+$'");
2155     }
2156 }
2157 TEST(ValidateRegulatorsConfigTest, Rule)
2158 {
2159     // valid test comments property, id property,
2160     // action property specified.
2161     {
2162         json configFile = validConfigFile;
2163         EXPECT_JSON_VALID(configFile);
2164     }
2165 
2166     // valid test rule with no comments
2167     {
2168         json configFile = validConfigFile;
2169         configFile["rules"][0].erase("comments");
2170         EXPECT_JSON_VALID(configFile);
2171     }
2172 
2173     // invalid test comments property has invalid value type
2174     {
2175         json configFile = validConfigFile;
2176         configFile["rules"][0]["comments"] = {1};
2177         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2178                             "1 is not of type 'string'");
2179     }
2180 
2181     // invalid test rule with no ID
2182     {
2183         json configFile = validConfigFile;
2184         configFile["rules"][0].erase("id");
2185         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2186                             "'id' is a required property");
2187     }
2188 
2189     // invalid test id property has invalid value type (not string)
2190     {
2191         json configFile = validConfigFile;
2192         configFile["rules"][0]["id"] = true;
2193         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2194                             "True is not of type 'string'");
2195     }
2196 
2197     // invalid test id property has invalid value
2198     {
2199         json configFile = validConfigFile;
2200         configFile["rules"][0]["id"] = "foo%";
2201         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2202                             "'foo%' does not match '^[A-Za-z0-9_]+$'");
2203     }
2204 
2205     // invalid test rule with no actions property
2206     {
2207         json configFile = validConfigFile;
2208         configFile["rules"][0].erase("actions");
2209         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2210                             "'actions' is a required property");
2211     }
2212 
2213     // valid test rule with multiple actions
2214     {
2215         json configFile = validConfigFile;
2216         configFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2217         EXPECT_JSON_VALID(configFile);
2218     }
2219 
2220     // invalid test actions property has invalid value type (not an array)
2221     {
2222         json configFile = validConfigFile;
2223         configFile["rules"][0]["actions"] = 1;
2224         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2225                             "1 is not of type 'array'");
2226     }
2227 
2228     // invalid test actions property has invalid value of action
2229     {
2230         json configFile = validConfigFile;
2231         configFile["rules"][0]["actions"][0] = "foo";
2232         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2233                             "'foo' is not of type 'object'");
2234     }
2235 
2236     // invalid test actions property has empty array
2237     {
2238         json configFile = validConfigFile;
2239         configFile["rules"][0]["actions"] = json::array();
2240         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2241                             "[] is too short");
2242     }
2243 }
2244 TEST(ValidateRegulatorsConfigTest, RunRule)
2245 {
2246     json runRuleFile = validConfigFile;
2247     runRuleFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2248     // Valid: test run_rule.
2249     {
2250         json configFile = runRuleFile;
2251         EXPECT_JSON_VALID(configFile);
2252     }
2253     // Invalid: test run_rule wrong type.
2254     {
2255         json configFile = runRuleFile;
2256         configFile["rules"][0]["actions"][1]["run_rule"] = true;
2257         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2258                             "True is not of type 'string'");
2259     }
2260     // Invalid: test run_rule wrong format.
2261     {
2262         json configFile = runRuleFile;
2263         configFile["rules"][0]["actions"][1]["run_rule"] = "set_voltage_rule%";
2264         EXPECT_JSON_INVALID(
2265             configFile, "Validation failed.",
2266             "'set_voltage_rule%' does not match '^[A-Za-z0-9_]+$'");
2267     }
2268 }
2269 TEST(ValidateRegulatorsConfigTest, SensorMonitoring)
2270 {
2271     // Valid: test rails sensor_monitoring with only property rule id.
2272     {
2273         json configFile = validConfigFile;
2274         EXPECT_JSON_VALID(configFile);
2275     }
2276     // Valid: test rails sensor_monitoring with only property actions.
2277     {
2278         json configFile = validConfigFile;
2279         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2280             .erase("rule_id");
2281         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2282                   ["actions"][0]["compare_presence"]["fru"] =
2283                       "/system/chassis/motherboard/cpu3";
2284         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2285                   ["actions"][0]["compare_presence"]["value"] = true;
2286         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2287                   ["comments"][0] = "comments";
2288         EXPECT_JSON_VALID(configFile);
2289     }
2290     // Invalid: test rails sensor_monitoring with both property rule_id and
2291     // actions.
2292     {
2293         json configFile = validConfigFile;
2294         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2295                   ["actions"][0]["compare_presence"]["fru"] =
2296                       "/system/chassis/motherboard/cpu3";
2297         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2298                   ["actions"][0]["compare_presence"]["value"] = true;
2299         EXPECT_JSON_INVALID(
2300             configFile, "Validation failed.",
2301             "{'actions': [{'compare_presence': {'fru': "
2302             "'/system/chassis/motherboard/cpu3', 'value': True}}], 'rule_id': "
2303             "'read_sensors_rule'} is valid under each of {'required': "
2304             "['actions']}, {'required': ['rule_id']}");
2305     }
2306     // Invalid: test rails sensor_monitoring with no rule_id and actions.
2307     {
2308         json configFile = validConfigFile;
2309         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2310             .erase("rule_id");
2311         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2312                             "'rule_id' is a required property");
2313     }
2314     // Invalid: test rails sensor_monitoring with property comments wrong type.
2315     {
2316         json configFile = validConfigFile;
2317         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2318                   ["comments"] = true;
2319         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2320                             "True is not of type 'array'");
2321     }
2322     // Invalid: test rails sensor_monitoring with property rule_id wrong type.
2323     {
2324         json configFile = validConfigFile;
2325         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2326                   ["rule_id"] = true;
2327         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2328                             "True is not of type 'string'");
2329     }
2330     // Invalid: test rails sensor_monitoring with property actions wrong type.
2331     {
2332         json configFile = validConfigFile;
2333         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2334             .erase("rule_id");
2335         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2336                   ["actions"] = true;
2337         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2338                             "True is not of type 'array'");
2339     }
2340     // Invalid: test rails sensor_monitoring with property rule_id wrong format.
2341     {
2342         json configFile = validConfigFile;
2343         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2344                   ["rule_id"] = "id@";
2345         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2346                             "'id@' does not match '^[A-Za-z0-9_]+$'");
2347     }
2348     // Invalid: test rails sensor_monitoring with property comments empty array.
2349     {
2350         json configFile = validConfigFile;
2351         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2352                   ["comments"] = json::array();
2353         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2354                             "[] is too short");
2355     }
2356     // Invalid: test rails sensor_monitoring with property actions empty array.
2357     {
2358         json configFile = validConfigFile;
2359         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2360             .erase("rule_id");
2361         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2362                   ["actions"] = json::array();
2363         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2364                             "[] is too short");
2365     }
2366 }
2367 TEST(ValidateRegulatorsConfigTest, SetDevice)
2368 {
2369     json setDeviceFile = validConfigFile;
2370     setDeviceFile["rules"][0]["actions"][1]["set_device"] = "vdd_regulator";
2371     // Valid: test set_device.
2372     {
2373         json configFile = setDeviceFile;
2374         EXPECT_JSON_VALID(configFile);
2375     }
2376     // Invalid: test set_device wrong type.
2377     {
2378         json configFile = setDeviceFile;
2379         configFile["rules"][0]["actions"][1]["set_device"] = true;
2380         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2381                             "True is not of type 'string'");
2382     }
2383     // Invalid: test set_device wrong format.
2384     {
2385         json configFile = setDeviceFile;
2386         configFile["rules"][0]["actions"][1]["set_device"] = "io_expander2%";
2387         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2388                             "'io_expander2%' does not match '^[A-Za-z0-9_]+$'");
2389     }
2390 }
2391 TEST(ValidateRegulatorsConfigTest, DuplicateRuleID)
2392 {
2393     // Invalid: test duplicate ID in rule.
2394     {
2395         json configFile = validConfigFile;
2396         configFile["rules"][2]["id"] = "set_voltage_rule";
2397         configFile["rules"][2]["actions"][0]["pmbus_write_vout_command"]
2398                   ["format"] = "linear";
2399         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rule ID.", "");
2400     }
2401 }
2402 TEST(ValidateRegulatorsConfigTest, DuplicateChassisNumber)
2403 {
2404     // Invalid: test duplicate number in chassis.
2405     {
2406         json configFile = validConfigFile;
2407         configFile["chassis"][1]["number"] = 1;
2408         EXPECT_JSON_INVALID(configFile, "Error: Duplicate chassis number.", "");
2409     }
2410 }
2411 TEST(ValidateRegulatorsConfigTest, DuplicateDeviceID)
2412 {
2413     // Invalid: test duplicate ID in device.
2414     {
2415         json configFile = validConfigFile;
2416         configFile["chassis"][0]["devices"][1]["id"] = "vdd_regulator";
2417         configFile["chassis"][0]["devices"][1]["is_regulator"] = true;
2418         configFile["chassis"][0]["devices"][1]["fru"] =
2419             "/system/chassis/motherboard/regulator1";
2420         configFile["chassis"][0]["devices"][1]["i2c_interface"]["bus"] = 2;
2421         configFile["chassis"][0]["devices"][1]["i2c_interface"]["address"] =
2422             "0x71";
2423         EXPECT_JSON_INVALID(configFile, "Error: Duplicate device ID.", "");
2424     }
2425 }
2426 TEST(ValidateRegulatorsConfigTest, DuplicateRailID)
2427 {
2428     // Invalid: test duplicate ID in rail.
2429     {
2430         json configFile = validConfigFile;
2431         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] = "vdd";
2432         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rail ID.", "");
2433     }
2434 }
2435 TEST(ValidateRegulatorsConfigTest, InfiniteLoops)
2436 {
2437     // Invalid: test run_rule with infinite loop (rules run each other).
2438     {
2439         json configFile = validConfigFile;
2440         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2441         configFile["rules"][2]["id"] = "set_voltage_rule1";
2442         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule1";
2443         configFile["rules"][3]["id"] = "set_voltage_rule2";
2444         EXPECT_JSON_INVALID(configFile,
2445                             "Infinite loop caused by run_rule actions.", "");
2446     }
2447     // Invalid: test run_rule with infinite loop (rule runs itself).
2448     {
2449         json configFile = validConfigFile;
2450         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule1";
2451         configFile["rules"][2]["id"] = "set_voltage_rule1";
2452         EXPECT_JSON_INVALID(configFile,
2453                             "Infinite loop caused by run_rule actions.", "");
2454     }
2455     // Invalid: test run_rule with infinite loop (indirect loop).
2456     {
2457         json configFile = validConfigFile;
2458         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2459         configFile["rules"][2]["id"] = "set_voltage_rule1";
2460         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule3";
2461         configFile["rules"][3]["id"] = "set_voltage_rule2";
2462         configFile["rules"][4]["actions"][0]["run_rule"] = "set_voltage_rule1";
2463         configFile["rules"][4]["id"] = "set_voltage_rule3";
2464         EXPECT_JSON_INVALID(configFile,
2465                             "Infinite loop caused by run_rule actions.", "");
2466     }
2467 }
2468 TEST(ValidateRegulatorsConfigTest, RunRuleValueExists)
2469 {
2470     // Invalid: test run_rule actions specify a rule ID that does not exist.
2471     {
2472         json configFile = validConfigFile;
2473         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2474         configFile["rules"][2]["id"] = "set_voltage_rule1";
2475         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2476     }
2477 }
2478 TEST(ValidateRegulatorsConfigTest, SetDeviceValueExists)
2479 {
2480     // Invalid: test set_device actions specify a device ID that does not exist.
2481     {
2482         json configFile = validConfigFile;
2483         configFile["rules"][2]["actions"][0]["set_device"] = "vdd_regulator2";
2484         configFile["rules"][2]["id"] = "set_voltage_rule1";
2485         EXPECT_JSON_INVALID(configFile, "Error: Device ID does not exist.", "");
2486     }
2487 }
2488 TEST(ValidateRegulatorsConfigTest, RuleIDExists)
2489 {
2490     // Invalid: test rule_id property in configuration specifies a rule ID that
2491     // does not exist.
2492     {
2493         json configFile = validConfigFile;
2494         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
2495             "set_voltage_rule2";
2496         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2497     }
2498     // Invalid: test rule_id property in presence_detection specifies a rule ID
2499     // that does not exist.
2500     {
2501         json configFile = validConfigFile;
2502         configFile["chassis"][0]["devices"][0]["presence_detection"]
2503                   ["rule_id"] = "set_voltage_rule2";
2504         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2505     }
2506     // Invalid: test rule_id property in sensor_monitoring specifies a rule ID
2507     // that does not exist.
2508     {
2509         json configFile = validConfigFile;
2510         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2511                   ["rule_id"] = "set_voltage_rule2";
2512         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2513     }
2514 }
2515 TEST(ValidateRegulatorsConfigTest, NumberOfElementsInMasks)
2516 {
2517     // Invalid: test number of elements in masks not equal to number in values
2518     // in i2c_compare_bytes.
2519     {
2520         json configFile = validConfigFile;
2521         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
2522             "0x82";
2523         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = {
2524             "0x02", "0x73"};
2525         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = {
2526             "0x7F"};
2527         EXPECT_JSON_INVALID(configFile,
2528                             "Error: Invalid i2c_compare_bytes action.", "");
2529     }
2530     // Invalid: test number of elements in masks not equal to number in values
2531     // in i2c_write_bytes.
2532     {
2533         json configFile = validConfigFile;
2534         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
2535             "0x82";
2536         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
2537             "0x02", "0x73"};
2538         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
2539             "0x7F"};
2540         EXPECT_JSON_INVALID(configFile,
2541                             "Error: Invalid i2c_write_bytes action.", "");
2542     }
2543 }
2544 TEST(ValidateRegulatorsConfigTest, CommandLineSyntax)
2545 {
2546     std::string validateTool =
2547         " ../phosphor-regulators/tools/validate-regulators-config.py ";
2548     std::string schema = " -s ";
2549     std::string schemaFile =
2550         " ../phosphor-regulators/schema/config_schema.json ";
2551     std::string configuration = " -c ";
2552     std::string command;
2553     std::string errorMessage;
2554     std::string outputMessage;
2555     std::string outputMessageHelp =
2556         "usage: validate-regulators-config.py [-h] [-s SCHEMA_FILE]";
2557     int valid = 0;
2558 
2559     std::string fileName;
2560     TmpFile tmpFile;
2561     fileName = tmpFile.getName();
2562     writeDataToFile(validConfigFile, fileName);
2563     // Valid: -s specified
2564     {
2565         command = validateTool + "-s " + schemaFile + configuration + fileName;
2566         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2567     }
2568     // Valid: --schema-file specified
2569     {
2570         command = validateTool + "--schema-file " + schemaFile + configuration +
2571                   fileName;
2572         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2573     }
2574     // Valid: -c specified
2575     {
2576         command = validateTool + schema + schemaFile + "-c " + fileName;
2577         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2578     }
2579     // Valid: --configuration-file specified
2580     {
2581         command = validateTool + schema + schemaFile + "--configuration-file " +
2582                   fileName;
2583         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2584     }
2585     // Valid: -h specified
2586     {
2587         command = validateTool + "-h ";
2588         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2589                                 valid);
2590     }
2591     // Valid: --help specified
2592     {
2593         command = validateTool + "--help ";
2594         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2595                                 valid);
2596     }
2597     // Invalid: -c/--configuration-file not specified
2598     {
2599         command = validateTool + schema + schemaFile;
2600         expectCommandLineSyntax("Error: Configuration file is required.",
2601                                 outputMessageHelp, command, 1);
2602     }
2603     // Invalid: -s/--schema-file not specified
2604     {
2605         command = validateTool + configuration + fileName;
2606         expectCommandLineSyntax("Error: Schema file is required.",
2607                                 outputMessageHelp, command, 1);
2608     }
2609     // Invalid: -s specified more than once
2610     {
2611         command =
2612             validateTool + "-s -s " + schemaFile + configuration + fileName;
2613         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2614     }
2615     // Invalid: -c specified more than once
2616     {
2617         command = validateTool + schema + schemaFile + "-c -c " + fileName;
2618         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2619     }
2620     // Invalid: No file name specified after -c
2621     {
2622         command = validateTool + schema + schemaFile + configuration;
2623         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2624     }
2625     // Invalid: No file name specified after -s
2626     {
2627         command = validateTool + schema + configuration + fileName;
2628         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2629     }
2630     // Invalid: File specified after -c does not exist
2631     {
2632         command = validateTool + schema + schemaFile + configuration +
2633                   "../notExistFile";
2634         expectCommandLineSyntax(
2635             "Traceback (most recent call last):", outputMessage, command, 1);
2636     }
2637     // Invalid: File specified after -s does not exist
2638     {
2639         command = validateTool + schema + "../notExistFile " + configuration +
2640                   fileName;
2641         expectCommandLineSyntax(
2642             "Traceback (most recent call last):", outputMessage, command, 1);
2643     }
2644     // Invalid: File specified after -s is not right data format
2645     {
2646         std::string wrongFormatFileName;
2647         TmpFile wrongFormatFile;
2648         wrongFormatFileName = wrongFormatFile.getName();
2649         std::ofstream out(wrongFormatFileName);
2650         out << "foo";
2651         out.close();
2652         command = validateTool + schema + wrongFormatFileName + configuration +
2653                   fileName;
2654         expectCommandLineSyntax(
2655             "Traceback (most recent call last):", outputMessage, command, 1);
2656     }
2657     // Invalid: File specified after -c is not readable
2658     {
2659         std::string notReadableFileName;
2660         TmpFile notReadableFile;
2661         notReadableFileName = notReadableFile.getName();
2662         writeDataToFile(validConfigFile, notReadableFileName);
2663         command = validateTool + schema + schemaFile + configuration +
2664                   notReadableFileName;
2665         chmod(notReadableFileName.c_str(), 0222);
2666         expectCommandLineSyntax(
2667             "Traceback (most recent call last):", outputMessage, command, 1);
2668     }
2669     // Invalid: File specified after -s is not readable
2670     {
2671         std::string notReadableFileName;
2672         TmpFile notReadableFile;
2673         notReadableFileName = notReadableFile.getName();
2674         writeDataToFile(validConfigFile, notReadableFileName);
2675         command = validateTool + schema + notReadableFileName + configuration +
2676                   fileName;
2677         chmod(notReadableFileName.c_str(), 0222);
2678         expectCommandLineSyntax(
2679             "Traceback (most recent call last):", outputMessage, command, 1);
2680     }
2681     // Invalid: Unexpected parameter specified (like -g)
2682     {
2683         command = validateTool + schema + schemaFile + configuration +
2684                   fileName + " -g";
2685         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2686     }
2687 }
2688