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