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 u'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                             "u'foo' is not of type u'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                             "u'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 u'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 u'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 u'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                             "u'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                             "u'' 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                             "u'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                             "u'1' is not of type u'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 u'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                             "u'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                             "u'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                             "u'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 u'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                             "u'' 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                             "u'Number' is not one of [u'CCIN', "
498                             "u'Manufacturer', u'Model', u'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 u'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 u'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             "{u'volts': 1.25, u'comments': [u'Set rail to 1.25V using standard "
577             "rule'], u'actions': [{u'compare_presence': {u'value': True, "
578             "u'fru': u'/system/chassis/motherboard/cpu3'}}], u'rule_id': "
579             "u'set_voltage_rule'} is valid under each of {u'required': "
580             "[u'actions']}, {u'required': [u'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                             "u'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 u'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 u'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 u'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                             "u'id!' does not match u'^[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                             "u'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                             "u'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                             "u'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                             "u'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 u'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 u'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 u'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 u'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 u'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 u'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 u'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 u'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                             "u'' 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                             "u'id#' does not match u'^[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                             "u'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                             "u'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                             "u'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 u'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                             "u'0xA00' does not match u'^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 u'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                             "u'1' is not of type u'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                             "u'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                             "u'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 u'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 u'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 u'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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'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                             "u'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 u'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 u'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 u'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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'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                             "u'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 u'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 u'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                             "u'0x700' does not match u'^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                             "u'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                             "u'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                             "u'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 u'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                             "u'0xA00' does not match u'^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 u'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                             "u'1' is not of type u'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                             "u'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                             "u'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 u'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 u'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 u'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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'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                             "u'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 u'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 u'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 u'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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x820' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'0x8' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'82' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'0xG1' does not match u'^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                             "u'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                             "u'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 u'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 u'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 u'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 u'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 u'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                             "u'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                             "u'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                             "u'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(
1852             configFile, "Validation failed.",
1853             "True is not one of [u'iout', u'iout_peak', u'iout_valley', "
1854             "u'pout', u'temperature', u'temperature_peak', u'vout', "
1855             "u'vout_peak', u'vout_valley']");
1856     }
1857     // Invalid: test pmbus_read_sensor with property command wrong type.
1858     {
1859         json configFile = pmbusReadSensorFile;
1860         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1861             true;
1862         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1863                             "True is not of type u'string'");
1864     }
1865     // Invalid: test pmbus_read_sensor with property format wrong type.
1866     {
1867         json configFile = pmbusReadSensorFile;
1868         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1869             true;
1870         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1871                             "True is not one of [u'linear_11', u'linear_16']");
1872     }
1873     // Invalid: test pmbus_read_sensor with property exponent wrong type.
1874     {
1875         json configFile = pmbusReadSensorFile;
1876         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["exponent"] =
1877             true;
1878         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1879                             "True is not of type u'integer'");
1880     }
1881     // Invalid: test pmbus_read_sensor with property type wrong format.
1882     {
1883         json configFile = pmbusReadSensorFile;
1884         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1885             "foo";
1886         EXPECT_JSON_INVALID(
1887             configFile, "Validation failed.",
1888             "u'foo' is not one of [u'iout', u'iout_peak', u'iout_valley', "
1889             "u'pout', u'temperature', u'temperature_peak', u'vout', "
1890             "u'vout_peak', u'vout_valley']");
1891     }
1892     // Invalid: test pmbus_read_sensor with property command wrong format.
1893     {
1894         json configFile = pmbusReadSensorFile;
1895         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1896             "0x8B0";
1897         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1898                             "u'0x8B0' does not match u'^0x[0-9a-fA-F]{2}$'");
1899     }
1900     // Invalid: test pmbus_read_sensor with property format wrong format.
1901     {
1902         json configFile = pmbusReadSensorFile;
1903         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1904             "foo";
1905         EXPECT_JSON_INVALID(
1906             configFile, "Validation failed.",
1907             "u'foo' is not one of [u'linear_11', u'linear_16']");
1908     }
1909 }
1910 TEST(ValidateRegulatorsConfigTest, PmbusWriteVoutCommand)
1911 {
1912     json pmbusWriteVoutCommandFile = validConfigFile;
1913     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1914                              ["pmbus_write_vout_command"]["volts"] = 1.03;
1915     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1916                              ["pmbus_write_vout_command"]["format"] = "linear";
1917     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1918                              ["pmbus_write_vout_command"]["exponent"] = -8;
1919     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
1920                              ["pmbus_write_vout_command"]["is_verified"] = true;
1921     // Valid: test pmbus_write_vout_command.
1922     {
1923         json configFile = pmbusWriteVoutCommandFile;
1924         EXPECT_JSON_VALID(configFile);
1925     }
1926     // Valid: test pmbus_write_vout_command with required properties.
1927     {
1928         json configFile = pmbusWriteVoutCommandFile;
1929         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1930             "volts");
1931         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1932             "exponent");
1933         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1934             "is_verified");
1935         EXPECT_JSON_VALID(configFile);
1936     }
1937     // Invalid: test pmbus_write_vout_command with no format.
1938     {
1939         json configFile = pmbusWriteVoutCommandFile;
1940         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
1941             "format");
1942         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1943                             "u'format' is a required property");
1944     }
1945     // Invalid: test pmbus_write_vout_command with property volts wrong type.
1946     {
1947         json configFile = pmbusWriteVoutCommandFile;
1948         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1949                   ["volts"] = true;
1950         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1951                             "True is not of type u'number'");
1952     }
1953     // Invalid: test pmbus_write_vout_command with property format wrong type.
1954     {
1955         json configFile = pmbusWriteVoutCommandFile;
1956         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1957                   ["format"] = true;
1958         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1959                             "True is not one of [u'linear']");
1960     }
1961     // Invalid: test pmbus_write_vout_command with property exponent wrong type.
1962     {
1963         json configFile = pmbusWriteVoutCommandFile;
1964         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1965                   ["exponent"] = 1.3;
1966         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1967                             "1.3 is not of type u'integer'");
1968     }
1969     // Invalid: test pmbus_write_vout_command with property is_verified wrong
1970     // type.
1971     {
1972         json configFile = pmbusWriteVoutCommandFile;
1973         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1974                   ["is_verified"] = 1;
1975         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1976                             "1 is not of type u'boolean'");
1977     }
1978     // Invalid: test pmbus_write_vout_command with property format wrong format.
1979     {
1980         json configFile = pmbusWriteVoutCommandFile;
1981         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
1982                   ["format"] = "foo";
1983         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1984                             "u'foo' is not one of [u'linear']");
1985     }
1986 }
1987 TEST(ValidateRegulatorsConfigTest, PresenceDetection)
1988 {
1989     json presenceDetectionFile = validConfigFile;
1990     presenceDetectionFile
1991         ["chassis"][0]["devices"][0]["presence_detection"]["comments"][0] =
1992             "Regulator is only present on the FooBar backplane";
1993     presenceDetectionFile["chassis"][0]["devices"][0]["presence_detection"]
1994                          ["rule_id"] = "set_voltage_rule";
1995     // Valid: test presence_detection with only property rule_id.
1996     {
1997         json configFile = presenceDetectionFile;
1998         EXPECT_JSON_VALID(configFile);
1999     }
2000     // Valid: test presence_detection with only property actions.
2001     {
2002         json configFile = presenceDetectionFile;
2003         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2004             "rule_id");
2005         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2006                   [0]["compare_presence"]["fru"] =
2007                       "/system/chassis/motherboard/cpu3";
2008         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2009                   [0]["compare_presence"]["value"] = true;
2010         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2011             "comments");
2012         EXPECT_JSON_VALID(configFile);
2013     }
2014     // Invalid: test presence_detection with both property rule_id and actions.
2015     {
2016         json configFile = presenceDetectionFile;
2017         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2018                   [0]["compare_presence"]["fru"] =
2019                       "/system/chassis/motherboard/cpu3";
2020         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2021                   [0]["compare_presence"]["value"] = true;
2022         EXPECT_JSON_INVALID(
2023             configFile, "Validation failed.",
2024             "{u'comments': [u'Regulator is only present on the FooBar "
2025             "backplane'], u'actions': [{u'compare_presence': {u'value': True, "
2026             "u'fru': u'/system/chassis/motherboard/cpu3'}}], u'rule_id': "
2027             "u'set_voltage_rule'} is valid under each of "
2028             "{u'required': [u'actions']}, {u'required': [u'rule_id']}");
2029     }
2030     // Invalid: test presence_detection with no rule_id and actions.
2031     {
2032         json configFile = presenceDetectionFile;
2033         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2034             "rule_id");
2035         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2036                             "u'rule_id' is a required property");
2037     }
2038     // Invalid: test presence_detection with property comments wrong type.
2039     {
2040         json configFile = presenceDetectionFile;
2041         configFile["chassis"][0]["devices"][0]["presence_detection"]
2042                   ["comments"] = true;
2043         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2044                             "True is not of type u'array'");
2045     }
2046     // Invalid: test presence_detection with property rule_id wrong type.
2047     {
2048         json configFile = presenceDetectionFile;
2049         configFile["chassis"][0]["devices"][0]["presence_detection"]
2050                   ["rule_id"] = true;
2051         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2052                             "True is not of type u'string'");
2053     }
2054     // Invalid: test presence_detection with property actions wrong type.
2055     {
2056         json configFile = presenceDetectionFile;
2057         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2058             "rule_id");
2059         configFile["chassis"][0]["devices"][0]["presence_detection"]
2060                   ["actions"] = true;
2061         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2062                             "True is not of type u'array'");
2063     }
2064     // Invalid: test presence_detection with property rule_id wrong format.
2065     {
2066         json configFile = presenceDetectionFile;
2067         configFile["chassis"][0]["devices"][0]["presence_detection"]
2068                   ["rule_id"] = "id@";
2069         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2070                             "u'id@' does not match u'^[A-Za-z0-9_]+$'");
2071     }
2072     // Invalid: test presence_detection with property comments empty array.
2073     {
2074         json configFile = presenceDetectionFile;
2075         configFile["chassis"][0]["devices"][0]["presence_detection"]
2076                   ["comments"] = json::array();
2077         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2078                             "[] is too short");
2079     }
2080     // Invalid: test presence_detection with property actions empty array.
2081     {
2082         json configFile = presenceDetectionFile;
2083         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2084             "rule_id");
2085         configFile["chassis"][0]["devices"][0]["presence_detection"]
2086                   ["actions"] = json::array();
2087         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2088                             "[] is too short");
2089     }
2090 }
2091 TEST(ValidateRegulatorsConfigTest, Rail)
2092 {
2093     // Valid: test rail.
2094     {
2095         json configFile = validConfigFile;
2096         EXPECT_JSON_VALID(configFile);
2097     }
2098     // Valid: test rail with required properties.
2099     {
2100         json configFile = validConfigFile;
2101         configFile["chassis"][0]["devices"][0]["rails"][0].erase("comments");
2102         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2103             "configuration");
2104         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2105             "sensor_monitoring");
2106         EXPECT_JSON_VALID(configFile);
2107     }
2108     // Invalid: test rail with no id.
2109     {
2110         json configFile = validConfigFile;
2111         configFile["chassis"][0]["devices"][0]["rails"][0].erase("id");
2112         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2113                             "u'id' is a required property");
2114     }
2115     // Invalid: test rail with comments wrong type.
2116     {
2117         json configFile = validConfigFile;
2118         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] = true;
2119         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2120                             "True is not of type u'array'");
2121     }
2122     // Invalid: test rail with id wrong type.
2123     {
2124         json configFile = validConfigFile;
2125         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = true;
2126         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2127                             "True is not of type u'string'");
2128     }
2129     // Invalid: test rail with configuration wrong type.
2130     {
2131         json configFile = validConfigFile;
2132         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"] =
2133             true;
2134         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2135                             "True is not of type u'object'");
2136     }
2137     // Invalid: test rail with sensor_monitoring wrong type.
2138     {
2139         json configFile = validConfigFile;
2140         configFile["chassis"][0]["devices"][0]["rails"][0]
2141                   ["sensor_monitoring"] = true;
2142         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2143                             "True is not of type u'object'");
2144     }
2145     // Invalid: test rail with comments empty array.
2146     {
2147         json configFile = validConfigFile;
2148         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] =
2149             json::array();
2150         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2151                             "[] is too short");
2152     }
2153     // Invalid: test rail with id wrong format.
2154     {
2155         json configFile = validConfigFile;
2156         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = "id~";
2157         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2158                             "u'id~' does not match u'^[A-Za-z0-9_]+$'");
2159     }
2160 }
2161 TEST(ValidateRegulatorsConfigTest, Rule)
2162 {
2163     // valid test comments property, id property,
2164     // action property specified.
2165     {
2166         json configFile = validConfigFile;
2167         EXPECT_JSON_VALID(configFile);
2168     }
2169 
2170     // valid test rule with no comments
2171     {
2172         json configFile = validConfigFile;
2173         configFile["rules"][0].erase("comments");
2174         EXPECT_JSON_VALID(configFile);
2175     }
2176 
2177     // invalid test comments property has invalid value type
2178     {
2179         json configFile = validConfigFile;
2180         configFile["rules"][0]["comments"] = {1};
2181         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2182                             "1 is not of type u'string'");
2183     }
2184 
2185     // invalid test rule with no ID
2186     {
2187         json configFile = validConfigFile;
2188         configFile["rules"][0].erase("id");
2189         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2190                             "u'id' is a required property");
2191     }
2192 
2193     // invalid test id property has invalid value type (not string)
2194     {
2195         json configFile = validConfigFile;
2196         configFile["rules"][0]["id"] = true;
2197         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2198                             "True is not of type u'string'");
2199     }
2200 
2201     // invalid test id property has invalid value
2202     {
2203         json configFile = validConfigFile;
2204         configFile["rules"][0]["id"] = "foo%";
2205         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2206                             "u'foo%' does not match u'^[A-Za-z0-9_]+$'");
2207     }
2208 
2209     // invalid test rule with no actions property
2210     {
2211         json configFile = validConfigFile;
2212         configFile["rules"][0].erase("actions");
2213         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2214                             "u'actions' is a required property");
2215     }
2216 
2217     // valid test rule with multiple actions
2218     {
2219         json configFile = validConfigFile;
2220         configFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2221         EXPECT_JSON_VALID(configFile);
2222     }
2223 
2224     // invalid test actions property has invalid value type (not an array)
2225     {
2226         json configFile = validConfigFile;
2227         configFile["rules"][0]["actions"] = 1;
2228         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2229                             "1 is not of type u'array'");
2230     }
2231 
2232     // invalid test actions property has invalid value of action
2233     {
2234         json configFile = validConfigFile;
2235         configFile["rules"][0]["actions"][0] = "foo";
2236         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2237                             "u'foo' is not of type u'object'");
2238     }
2239 
2240     // invalid test actions property has empty array
2241     {
2242         json configFile = validConfigFile;
2243         configFile["rules"][0]["actions"] = json::array();
2244         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2245                             "[] is too short");
2246     }
2247 }
2248 TEST(ValidateRegulatorsConfigTest, RunRule)
2249 {
2250     json runRuleFile = validConfigFile;
2251     runRuleFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2252     // Valid: test run_rule.
2253     {
2254         json configFile = runRuleFile;
2255         EXPECT_JSON_VALID(configFile);
2256     }
2257     // Invalid: test run_rule wrong type.
2258     {
2259         json configFile = runRuleFile;
2260         configFile["rules"][0]["actions"][1]["run_rule"] = true;
2261         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2262                             "True is not of type u'string'");
2263     }
2264     // Invalid: test run_rule wrong format.
2265     {
2266         json configFile = runRuleFile;
2267         configFile["rules"][0]["actions"][1]["run_rule"] = "set_voltage_rule%";
2268         EXPECT_JSON_INVALID(
2269             configFile, "Validation failed.",
2270             "u'set_voltage_rule%' does not match u'^[A-Za-z0-9_]+$'");
2271     }
2272 }
2273 TEST(ValidateRegulatorsConfigTest, SensorMonitoring)
2274 {
2275     // Valid: test rails sensor_monitoring with only property rule id.
2276     {
2277         json configFile = validConfigFile;
2278         EXPECT_JSON_VALID(configFile);
2279     }
2280     // Valid: test rails sensor_monitoring with only property actions.
2281     {
2282         json configFile = validConfigFile;
2283         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2284             .erase("rule_id");
2285         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2286                   ["actions"][0]["compare_presence"]["fru"] =
2287                       "/system/chassis/motherboard/cpu3";
2288         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2289                   ["actions"][0]["compare_presence"]["value"] = true;
2290         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2291                   ["comments"][0] = "comments";
2292         EXPECT_JSON_VALID(configFile);
2293     }
2294     // Invalid: test rails sensor_monitoring with both property rule_id and
2295     // actions.
2296     {
2297         json configFile = validConfigFile;
2298         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2299                   ["actions"][0]["compare_presence"]["fru"] =
2300                       "/system/chassis/motherboard/cpu3";
2301         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2302                   ["actions"][0]["compare_presence"]["value"] = true;
2303         EXPECT_JSON_INVALID(
2304             configFile, "Validation failed.",
2305             "{u'rule_id': u'read_sensors_rule', u'actions': "
2306             "[{u'compare_presence': {u'value': True, u'fru': "
2307             "u'/system/chassis/motherboard/cpu3'}}]} is valid under each of "
2308             "{u'required': [u'actions']}, {u'required': [u'rule_id']}");
2309     }
2310     // Invalid: test rails sensor_monitoring with no rule_id and actions.
2311     {
2312         json configFile = validConfigFile;
2313         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2314             .erase("rule_id");
2315         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2316                             "u'rule_id' is a required property");
2317     }
2318     // Invalid: test rails sensor_monitoring with property comments wrong type.
2319     {
2320         json configFile = validConfigFile;
2321         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2322                   ["comments"] = true;
2323         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2324                             "True is not of type u'array'");
2325     }
2326     // Invalid: test rails sensor_monitoring with property rule_id wrong type.
2327     {
2328         json configFile = validConfigFile;
2329         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2330                   ["rule_id"] = true;
2331         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2332                             "True is not of type u'string'");
2333     }
2334     // Invalid: test rails sensor_monitoring with property actions wrong type.
2335     {
2336         json configFile = validConfigFile;
2337         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2338             .erase("rule_id");
2339         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2340                   ["actions"] = true;
2341         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2342                             "True is not of type u'array'");
2343     }
2344     // Invalid: test rails sensor_monitoring with property rule_id wrong format.
2345     {
2346         json configFile = validConfigFile;
2347         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2348                   ["rule_id"] = "id@";
2349         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2350                             "u'id@' does not match u'^[A-Za-z0-9_]+$'");
2351     }
2352     // Invalid: test rails sensor_monitoring with property comments empty array.
2353     {
2354         json configFile = validConfigFile;
2355         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2356                   ["comments"] = json::array();
2357         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2358                             "[] is too short");
2359     }
2360     // Invalid: test rails sensor_monitoring with property actions empty array.
2361     {
2362         json configFile = validConfigFile;
2363         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2364             .erase("rule_id");
2365         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2366                   ["actions"] = json::array();
2367         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2368                             "[] is too short");
2369     }
2370 }
2371 TEST(ValidateRegulatorsConfigTest, SetDevice)
2372 {
2373     json setDeviceFile = validConfigFile;
2374     setDeviceFile["rules"][0]["actions"][1]["set_device"] = "vdd_regulator";
2375     // Valid: test set_device.
2376     {
2377         json configFile = setDeviceFile;
2378         EXPECT_JSON_VALID(configFile);
2379     }
2380     // Invalid: test set_device wrong type.
2381     {
2382         json configFile = setDeviceFile;
2383         configFile["rules"][0]["actions"][1]["set_device"] = true;
2384         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2385                             "True is not of type u'string'");
2386     }
2387     // Invalid: test set_device wrong format.
2388     {
2389         json configFile = setDeviceFile;
2390         configFile["rules"][0]["actions"][1]["set_device"] = "io_expander2%";
2391         EXPECT_JSON_INVALID(
2392             configFile, "Validation failed.",
2393             "u'io_expander2%' does not match u'^[A-Za-z0-9_]+$'");
2394     }
2395 }
2396 TEST(ValidateRegulatorsConfigTest, DuplicateRuleID)
2397 {
2398     // Invalid: test duplicate ID in rule.
2399     {
2400         json configFile = validConfigFile;
2401         configFile["rules"][2]["id"] = "set_voltage_rule";
2402         configFile["rules"][2]["actions"][0]["pmbus_write_vout_command"]
2403                   ["format"] = "linear";
2404         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rule ID.", "");
2405     }
2406 }
2407 TEST(ValidateRegulatorsConfigTest, DuplicateChassisNumber)
2408 {
2409     // Invalid: test duplicate number in chassis.
2410     {
2411         json configFile = validConfigFile;
2412         configFile["chassis"][1]["number"] = 1;
2413         EXPECT_JSON_INVALID(configFile, "Error: Duplicate chassis number.", "");
2414     }
2415 }
2416 TEST(ValidateRegulatorsConfigTest, DuplicateDeviceID)
2417 {
2418     // Invalid: test duplicate ID in device.
2419     {
2420         json configFile = validConfigFile;
2421         configFile["chassis"][0]["devices"][1]["id"] = "vdd_regulator";
2422         configFile["chassis"][0]["devices"][1]["is_regulator"] = true;
2423         configFile["chassis"][0]["devices"][1]["fru"] =
2424             "/system/chassis/motherboard/regulator1";
2425         configFile["chassis"][0]["devices"][1]["i2c_interface"]["bus"] = 2;
2426         configFile["chassis"][0]["devices"][1]["i2c_interface"]["address"] =
2427             "0x71";
2428         EXPECT_JSON_INVALID(configFile, "Error: Duplicate device ID.", "");
2429     }
2430 }
2431 TEST(ValidateRegulatorsConfigTest, DuplicateRailID)
2432 {
2433     // Invalid: test duplicate ID in rail.
2434     {
2435         json configFile = validConfigFile;
2436         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] = "vdd";
2437         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rail ID.", "");
2438     }
2439 }
2440 TEST(ValidateRegulatorsConfigTest, InfiniteLoops)
2441 {
2442     // Invalid: test run_rule with infinite loop (rules run each other).
2443     {
2444         json configFile = validConfigFile;
2445         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2446         configFile["rules"][2]["id"] = "set_voltage_rule1";
2447         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule1";
2448         configFile["rules"][3]["id"] = "set_voltage_rule2";
2449         EXPECT_JSON_INVALID(configFile,
2450                             "Infinite loop caused by run_rule actions.", "");
2451     }
2452     // Invalid: test run_rule with infinite loop (rule runs itself).
2453     {
2454         json configFile = validConfigFile;
2455         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule1";
2456         configFile["rules"][2]["id"] = "set_voltage_rule1";
2457         EXPECT_JSON_INVALID(configFile,
2458                             "Infinite loop caused by run_rule actions.", "");
2459     }
2460     // Invalid: test run_rule with infinite loop (indirect loop).
2461     {
2462         json configFile = validConfigFile;
2463         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2464         configFile["rules"][2]["id"] = "set_voltage_rule1";
2465         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule3";
2466         configFile["rules"][3]["id"] = "set_voltage_rule2";
2467         configFile["rules"][4]["actions"][0]["run_rule"] = "set_voltage_rule1";
2468         configFile["rules"][4]["id"] = "set_voltage_rule3";
2469         EXPECT_JSON_INVALID(configFile,
2470                             "Infinite loop caused by run_rule actions.", "");
2471     }
2472 }
2473 TEST(ValidateRegulatorsConfigTest, RunRuleValueExists)
2474 {
2475     // Invalid: test run_rule actions specify a rule ID that does not exist.
2476     {
2477         json configFile = validConfigFile;
2478         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2479         configFile["rules"][2]["id"] = "set_voltage_rule1";
2480         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2481     }
2482 }
2483 TEST(ValidateRegulatorsConfigTest, SetDeviceValueExists)
2484 {
2485     // Invalid: test set_device actions specify a device ID that does not exist.
2486     {
2487         json configFile = validConfigFile;
2488         configFile["rules"][2]["actions"][0]["set_device"] = "vdd_regulator2";
2489         configFile["rules"][2]["id"] = "set_voltage_rule1";
2490         EXPECT_JSON_INVALID(configFile, "Error: Device ID does not exist.", "");
2491     }
2492 }
2493 TEST(ValidateRegulatorsConfigTest, RuleIDExists)
2494 {
2495     // Invalid: test rule_id property in configuration specifies a rule ID that
2496     // does not exist.
2497     {
2498         json configFile = validConfigFile;
2499         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
2500             "set_voltage_rule2";
2501         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2502     }
2503     // Invalid: test rule_id property in presence_detection specifies a rule ID
2504     // that does not exist.
2505     {
2506         json configFile = validConfigFile;
2507         configFile["chassis"][0]["devices"][0]["presence_detection"]
2508                   ["rule_id"] = "set_voltage_rule2";
2509         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2510     }
2511     // Invalid: test rule_id property in sensor_monitoring specifies a rule ID
2512     // that does not exist.
2513     {
2514         json configFile = validConfigFile;
2515         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2516                   ["rule_id"] = "set_voltage_rule2";
2517         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2518     }
2519 }
2520 TEST(ValidateRegulatorsConfigTest, NumberOfElementsInMasks)
2521 {
2522     // Invalid: test number of elements in masks not equal to number in values
2523     // in i2c_compare_bytes.
2524     {
2525         json configFile = validConfigFile;
2526         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
2527             "0x82";
2528         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = {
2529             "0x02", "0x73"};
2530         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = {
2531             "0x7F"};
2532         EXPECT_JSON_INVALID(configFile,
2533                             "Error: Invalid i2c_compare_bytes action.", "");
2534     }
2535     // Invalid: test number of elements in masks not equal to number in values
2536     // in i2c_write_bytes.
2537     {
2538         json configFile = validConfigFile;
2539         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
2540             "0x82";
2541         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
2542             "0x02", "0x73"};
2543         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
2544             "0x7F"};
2545         EXPECT_JSON_INVALID(configFile,
2546                             "Error: Invalid i2c_write_bytes action.", "");
2547     }
2548 }
2549 TEST(ValidateRegulatorsConfigTest, CommandLineSyntax)
2550 {
2551     std::string validateTool =
2552         " ../phosphor-regulators/tools/validate-regulators-config.py ";
2553     std::string schema = " -s ";
2554     std::string schemaFile =
2555         " ../phosphor-regulators/schema/config_schema.json ";
2556     std::string configuration = " -c ";
2557     std::string command;
2558     std::string errorMessage;
2559     std::string outputMessage;
2560     std::string outputMessageHelp =
2561         "usage: validate-regulators-config.py [-h] [-s SCHEMA_FILE]";
2562     int valid = 0;
2563 
2564     std::string fileName;
2565     TmpFile tmpFile;
2566     fileName = tmpFile.getName();
2567     writeDataToFile(validConfigFile, fileName);
2568     // Valid: -s specified
2569     {
2570         command = validateTool + "-s " + schemaFile + configuration + fileName;
2571         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2572     }
2573     // Valid: --schema-file specified
2574     {
2575         command = validateTool + "--schema-file " + schemaFile + configuration +
2576                   fileName;
2577         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2578     }
2579     // Valid: -c specified
2580     {
2581         command = validateTool + schema + schemaFile + "-c " + fileName;
2582         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2583     }
2584     // Valid: --configuration-file specified
2585     {
2586         command = validateTool + schema + schemaFile + "--configuration-file " +
2587                   fileName;
2588         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2589     }
2590     // Valid: -h specified
2591     {
2592         command = validateTool + "-h ";
2593         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2594                                 valid);
2595     }
2596     // Valid: --help specified
2597     {
2598         command = validateTool + "--help ";
2599         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2600                                 valid);
2601     }
2602     // Invalid: -c/--configuration-file not specified
2603     {
2604         command = validateTool + schema + schemaFile;
2605         expectCommandLineSyntax("Error: Configuration file is required.",
2606                                 outputMessageHelp, command, 1);
2607     }
2608     // Invalid: -s/--schema-file not specified
2609     {
2610         command = validateTool + configuration + fileName;
2611         expectCommandLineSyntax("Error: Schema file is required.",
2612                                 outputMessageHelp, command, 1);
2613     }
2614     // Invalid: -s specified more than once
2615     {
2616         command =
2617             validateTool + "-s -s " + schemaFile + configuration + fileName;
2618         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2619     }
2620     // Invalid: -c specified more than once
2621     {
2622         command = validateTool + schema + schemaFile + "-c -c " + fileName;
2623         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2624     }
2625     // Invalid: No file name specified after -c
2626     {
2627         command = validateTool + schema + schemaFile + configuration;
2628         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2629     }
2630     // Invalid: No file name specified after -s
2631     {
2632         command = validateTool + schema + configuration + fileName;
2633         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2634     }
2635     // Invalid: File specified after -c does not exist
2636     {
2637         command = validateTool + schema + schemaFile + configuration +
2638                   "../notExistFile";
2639         expectCommandLineSyntax(
2640             "Traceback (most recent call last):", outputMessage, command, 1);
2641     }
2642     // Invalid: File specified after -s does not exist
2643     {
2644         command = validateTool + schema + "../notExistFile " + configuration +
2645                   fileName;
2646         expectCommandLineSyntax(
2647             "Traceback (most recent call last):", outputMessage, command, 1);
2648     }
2649     // Invalid: File specified after -s is not right data format
2650     {
2651         std::string wrongFormatFileName;
2652         TmpFile wrongFormatFile;
2653         wrongFormatFileName = wrongFormatFile.getName();
2654         std::ofstream out(wrongFormatFileName);
2655         out << "foo";
2656         out.close();
2657         command = validateTool + schema + wrongFormatFileName + configuration +
2658                   fileName;
2659         expectCommandLineSyntax(
2660             "Traceback (most recent call last):", outputMessage, command, 1);
2661     }
2662     // Invalid: File specified after -c is not readable
2663     {
2664         std::string notReadableFileName;
2665         TmpFile notReadableFile;
2666         notReadableFileName = notReadableFile.getName();
2667         writeDataToFile(validConfigFile, notReadableFileName);
2668         command = validateTool + schema + schemaFile + configuration +
2669                   notReadableFileName;
2670         chmod(notReadableFileName.c_str(), 0222);
2671         expectCommandLineSyntax(
2672             "Traceback (most recent call last):", outputMessage, command, 1);
2673     }
2674     // Invalid: File specified after -s is not readable
2675     {
2676         std::string notReadableFileName;
2677         TmpFile notReadableFile;
2678         notReadableFileName = notReadableFile.getName();
2679         writeDataToFile(validConfigFile, notReadableFileName);
2680         command = validateTool + schema + notReadableFileName + configuration +
2681                   fileName;
2682         chmod(notReadableFileName.c_str(), 0222);
2683         expectCommandLineSyntax(
2684             "Traceback (most recent call last):", outputMessage, command, 1);
2685     }
2686     // Invalid: Unexpected parameter specified (like -g)
2687     {
2688         command = validateTool + schema + schemaFile + configuration +
2689                   fileName + " -g";
2690         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2691     }
2692 }
2693