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