blob: 98321e429b98366ae4f49a2fe577d15e317f702a [file] [log] [blame]
Bob King386d33f2019-12-26 17:28:56 +08001/**
Bob King0dcbdf52020-01-20 17:19:39 +08002 * Copyright c 2020 IBM Corporation
Bob King386d33f2019-12-26 17:28:56 +08003 *
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
Bob King386d33f2019-12-26 17:28:56 +080021#include <nlohmann/json.hpp>
22
Bob King0dcbdf52020-01-20 17:19:39 +080023#include <fstream>
24
Bob King386d33f2019-12-26 17:28:56 +080025#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
37using json = nlohmann::json;
38
39const 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
91std::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
104std::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
112int 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
153void 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
163void 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
175void 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
188void 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
203TEST(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 }
Bob King0dcbdf52020-01-20 17:19:39 +0800290}
Bob Kingbeaf6532020-01-21 11:03:49 +0800291TEST(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}
Bob Kingbf1cbea2020-01-21 11:08:50 +0800351TEST(ValidateRegulatorsConfigTest, ComparePresence)
352{
353 json comparePresenceFile = validConfigFile;
354 comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
355 "/system/chassis/motherboard/regulator2";
356 comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
357 true;
358 // Valid.
359 {
360 json configFile = comparePresenceFile;
361 EXPECT_JSON_VALID(configFile);
362 }
363
364 // Invalid: no FRU property.
365 {
366 json configFile = comparePresenceFile;
367 configFile["rules"][0]["actions"][1]["compare_presence"].erase("fru");
368 EXPECT_JSON_INVALID(configFile, "Validation failed.",
369 "u'fru' is a required property");
370 }
371
372 // Invalid: FRU property length is string less than 1.
373 {
374 json configFile = comparePresenceFile;
375 configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = "";
376 EXPECT_JSON_INVALID(configFile, "Validation failed.",
377 "u'' is too short");
378 }
379
380 // Invalid: no value property.
381 {
382 json configFile = comparePresenceFile;
383 configFile["rules"][0]["actions"][1]["compare_presence"].erase("value");
384 EXPECT_JSON_INVALID(configFile, "Validation failed.",
385 "u'value' is a required property");
386 }
387
388 // Invalid: value property type is not boolean.
389 {
390 json configFile = comparePresenceFile;
391 configFile["rules"][0]["actions"][1]["compare_presence"]["value"] = "1";
392 EXPECT_JSON_INVALID(configFile, "Validation failed.",
393 "u'1' is not of type u'boolean'");
394 }
395
396 // Invalid: FRU property type is not string.
397 {
398 json configFile = comparePresenceFile;
399 configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = 1;
400 EXPECT_JSON_INVALID(configFile, "Validation failed.",
401 "1 is not of type u'string'");
402 }
403}
Bob Kingf8b77a02020-01-21 11:09:47 +0800404TEST(ValidateRegulatorsConfigTest, CompareVpd)
405{
406 json compareVpdFile = validConfigFile;
407 compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
408 "/system/chassis/motherboard/regulator2";
409 compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
410 compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
411
412 // Valid.
413 {
414 json configFile = compareVpdFile;
415 EXPECT_JSON_VALID(configFile);
416 }
417
418 // Invalid: no FRU property.
419 {
420 json configFile = compareVpdFile;
421 configFile["rules"][0]["actions"][1]["compare_vpd"].erase("fru");
422 EXPECT_JSON_INVALID(configFile, "Validation failed.",
423 "u'fru' is a required property");
424 }
425
426 // Invalid: no keyword property.
427 {
428 json configFile = compareVpdFile;
429 configFile["rules"][0]["actions"][1]["compare_vpd"].erase("keyword");
430 EXPECT_JSON_INVALID(configFile, "Validation failed.",
431 "u'keyword' is a required property");
432 }
433
434 // Invalid: no value property.
435 {
436 json configFile = compareVpdFile;
437 configFile["rules"][0]["actions"][1]["compare_vpd"].erase("value");
438 EXPECT_JSON_INVALID(configFile, "Validation failed.",
439 "u'value' is a required property");
440 }
441
442 // Invalid: property FRU wrong type.
443 {
444 json configFile = compareVpdFile;
445 configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = 1;
446 EXPECT_JSON_INVALID(configFile, "Validation failed.",
447 "1 is not of type u'string'");
448 }
449
450 // Invalid: property FRU is string less than 1.
451 {
452 json configFile = compareVpdFile;
453 configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = "";
454 EXPECT_JSON_INVALID(configFile, "Validation failed.",
455 "u'' is too short");
456 }
457
458 // Invalid: property keyword is not "CCIN", "Manufacturer", "Model",
459 // "PartNumber"
460 {
461 json configFile = compareVpdFile;
462 configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] =
463 "Number";
464 EXPECT_JSON_INVALID(configFile, "Validation failed.",
465 "u'Number' is not one of [u'CCIN', "
466 "u'Manufacturer', u'Model', u'PartNumber']");
467 }
468
469 // Invalid: property value wrong type.
470 {
471 json configFile = compareVpdFile;
472 configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = 1;
473 EXPECT_JSON_INVALID(configFile, "Validation failed.",
474 "1 is not of type u'string'");
475 }
476}
Bob King4ab8cbb2020-01-21 11:10:48 +0800477TEST(ValidateRegulatorsConfigTest, I2CCompareBit)
478{
479 json i2cCompareBitFile = validConfigFile;
480 i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
481 "0xA0";
482 i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
483 3;
484 i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
485 // Valid: test rule actions i2c_compare_bit.
486 {
487 json configFile = i2cCompareBitFile;
488 EXPECT_JSON_VALID(configFile);
489 }
490 // Invalid: test i2c_compare_bit with no register.
491 {
492 json configFile = i2cCompareBitFile;
493 configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
494 "register");
495 EXPECT_JSON_INVALID(configFile, "Validation failed.",
496 "u'register' is a required property");
497 }
498 // Invalid: test i2c_compare_bit with no position.
499 {
500 json configFile = i2cCompareBitFile;
501 configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
502 "position");
503 EXPECT_JSON_INVALID(configFile, "Validation failed.",
504 "u'position' is a required property");
505 }
506 // Invalid: test i2c_compare_bit with no value.
507 {
508 json configFile = i2cCompareBitFile;
509 configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase("value");
510 EXPECT_JSON_INVALID(configFile, "Validation failed.",
511 "u'value' is a required property");
512 }
513 // Invalid: test i2c_compare_bit with register wrong type.
514 {
515 json configFile = i2cCompareBitFile;
516 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] = 1;
517 EXPECT_JSON_INVALID(configFile, "Validation failed.",
518 "1 is not of type u'string'");
519 }
520 // Invalid: test i2c_compare_bit with register wrong format.
521 {
522 json configFile = i2cCompareBitFile;
523 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
524 "0xA00";
525 EXPECT_JSON_INVALID(configFile, "Validation failed.",
526 "u'0xA00' does not match u'^0x[0-9A-Fa-f]{2}$'");
527 }
528 // Invalid: test i2c_compare_bit with position wrong type.
529 {
530 json configFile = i2cCompareBitFile;
531 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
532 3.1;
533 EXPECT_JSON_INVALID(configFile, "Validation failed.",
534 "3.1 is not of type u'integer'");
535 }
536 // Invalid: test i2c_compare_bit with position greater than 7.
537 {
538 json configFile = i2cCompareBitFile;
539 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 8;
540 EXPECT_JSON_INVALID(configFile, "Validation failed.",
541 "8 is greater than the maximum of 7");
542 }
543 // Invalid: test i2c_compare_bit with position less than 0.
544 {
545 json configFile = i2cCompareBitFile;
546 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
547 -1;
548 EXPECT_JSON_INVALID(configFile, "Validation failed.",
549 "-1 is less than the minimum of 0");
550 }
551 // Invalid: test i2c_compare_bit with value wrong type.
552 {
553 json configFile = i2cCompareBitFile;
554 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = "1";
555 EXPECT_JSON_INVALID(configFile, "Validation failed.",
556 "u'1' is not of type u'integer'");
557 }
558 // Invalid: test i2c_compare_bit with value greater than 1.
559 {
560 json configFile = i2cCompareBitFile;
561 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 2;
562 EXPECT_JSON_INVALID(configFile, "Validation failed.",
563 "2 is greater than the maximum of 1");
564 }
565 // Invalid: test i2c_compare_bit with value less than 0.
566 {
567 json configFile = i2cCompareBitFile;
568 configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = -1;
569 EXPECT_JSON_INVALID(configFile, "Validation failed.",
570 "-1 is less than the minimum of 0");
571 }
572}
Bob King514023d2020-01-21 11:13:05 +0800573TEST(ValidateRegulatorsConfigTest, I2CCompareByte)
574{
575 json i2cCompareByteFile = validConfigFile;
576 i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]
577 ["register"] = "0x82";
578 i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
579 "0x40";
580 i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
581 "0x7F";
582 // Valid: test i2c_compare_byte with all properties.
583 {
584 json configFile = i2cCompareByteFile;
585 EXPECT_JSON_VALID(configFile);
586 }
587 // Valid: test i2c_compare_byte with all required properties.
588 {
589 json configFile = i2cCompareByteFile;
590 configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("mask");
591 EXPECT_JSON_VALID(configFile);
592 }
593 // Invalid: test i2c_compare_byte with no register.
594 {
595 json configFile = i2cCompareByteFile;
596 configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase(
597 "register");
598 EXPECT_JSON_INVALID(configFile, "Validation failed.",
599 "u'register' is a required property");
600 }
601 // Invalid: test i2c_compare_byte with no value.
602 {
603 json configFile = i2cCompareByteFile;
604 configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("value");
605 EXPECT_JSON_INVALID(configFile, "Validation failed.",
606 "u'value' is a required property");
607 }
608 // Invalid: test i2c_compare_byte with property register wrong type.
609 {
610 json configFile = i2cCompareByteFile;
611 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
612 1;
613 EXPECT_JSON_INVALID(configFile, "Validation failed.",
614 "1 is not of type u'string'");
615 }
616 // Invalid: test i2c_compare_byte with property value wrong type.
617 {
618 json configFile = i2cCompareByteFile;
619 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] = 1;
620 EXPECT_JSON_INVALID(configFile, "Validation failed.",
621 "1 is not of type u'string'");
622 }
623 // Invalid: test i2c_compare_byte with property mask wrong type.
624 {
625 json configFile = i2cCompareByteFile;
626 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = 1;
627 EXPECT_JSON_INVALID(configFile, "Validation failed.",
628 "1 is not of type u'string'");
629 }
630 // Invalid: test i2c_compare_byte with property register more than 2 hex
631 // digits.
632 {
633 json configFile = i2cCompareByteFile;
634 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
635 "0x820";
636 EXPECT_JSON_INVALID(configFile, "Validation failed.",
637 "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
638 }
639 // Invalid: test i2c_compare_byte with property value more than 2 hex
640 // digits.
641 {
642 json configFile = i2cCompareByteFile;
643 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
644 "0x820";
645 EXPECT_JSON_INVALID(configFile, "Validation failed.",
646 "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
647 }
648 // Invalid: test i2c_compare_byte with property mask more than 2 hex digits.
649 {
650 json configFile = i2cCompareByteFile;
651 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
652 "0x820";
653 EXPECT_JSON_INVALID(configFile, "Validation failed.",
654 "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
655 }
656 // Invalid: test i2c_compare_byte with property register less than 2 hex
657 // digits.
658 {
659 json configFile = i2cCompareByteFile;
660 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
661 "0x8";
662 EXPECT_JSON_INVALID(configFile, "Validation failed.",
663 "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
664 }
665 // Invalid: test i2c_compare_byte with property value less than 2 hex
666 // digits.
667 {
668 json configFile = i2cCompareByteFile;
669 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
670 "0x8";
671 EXPECT_JSON_INVALID(configFile, "Validation failed.",
672 "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
673 }
674 // Invalid: test i2c_compare_byte with property mask less than 2 hex digits.
675 {
676 json configFile = i2cCompareByteFile;
677 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
678 "0x8";
679 EXPECT_JSON_INVALID(configFile, "Validation failed.",
680 "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
681 }
682 // Invalid: test i2c_compare_byte with property register no leading prefix.
683 {
684 json configFile = i2cCompareByteFile;
685 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
686 "82";
687 EXPECT_JSON_INVALID(configFile, "Validation failed.",
688 "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
689 }
690 // Invalid: test i2c_compare_byte with property value no leading prefix.
691 {
692 json configFile = i2cCompareByteFile;
693 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
694 "82";
695 EXPECT_JSON_INVALID(configFile, "Validation failed.",
696 "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
697 }
698 // Invalid: test i2c_compare_byte with property mask no leading prefix.
699 {
700 json configFile = i2cCompareByteFile;
701 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = "82";
702 EXPECT_JSON_INVALID(configFile, "Validation failed.",
703 "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
704 }
705 // Invalid: test i2c_compare_byte with property register invalid hex digit.
706 {
707 json configFile = i2cCompareByteFile;
708 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
709 "0xG1";
710 EXPECT_JSON_INVALID(configFile, "Validation failed.",
711 "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
712 }
713 // Invalid: test i2c_compare_byte with property value invalid hex digit.
714 {
715 json configFile = i2cCompareByteFile;
716 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
717 "0xG1";
718 EXPECT_JSON_INVALID(configFile, "Validation failed.",
719 "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
720 }
721 // Invalid: test i2c_compare_byte with property mask invalid hex digit.
722 {
723 json configFile = i2cCompareByteFile;
724 configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
725 "0xG1";
726 EXPECT_JSON_INVALID(configFile, "Validation failed.",
727 "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
728 }
729}
Bob Kingfb162bb2020-01-21 11:28:07 +0800730TEST(ValidateRegulatorsConfigTest, I2CCompareBytes)
731{
732 json i2cCompareBytesFile = validConfigFile;
733 i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
734 ["register"] = "0x82";
735 i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
736 ["values"] = {"0x02", "0x73"};
737 i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
738 ["masks"] = {"0x7F", "0x7F"};
739 // Valid: test i2c_compare_bytes.
740 {
741 json configFile = i2cCompareBytesFile;
742 EXPECT_JSON_VALID(configFile);
743 }
744 // Valid: test i2c_compare_bytes with all required properties.
745 {
746 json configFile = i2cCompareBytesFile;
747 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
748 "masks");
749 EXPECT_JSON_VALID(configFile);
750 }
751 // Invalid: test i2c_compare_bytes with no register.
752 {
753 json configFile = i2cCompareBytesFile;
754 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
755 "register");
756 EXPECT_JSON_INVALID(configFile, "Validation failed.",
757 "u'register' is a required property");
758 }
759 // Invalid: test i2c_compare_bytes with no values.
760 {
761 json configFile = i2cCompareBytesFile;
762 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
763 "values");
764 EXPECT_JSON_INVALID(configFile, "Validation failed.",
765 "u'values' is a required property");
766 }
767 // Invalid: test i2c_compare_bytes with property values as empty array.
768 {
769 json configFile = i2cCompareBytesFile;
770 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] =
771 json::array();
772 EXPECT_JSON_INVALID(configFile, "Validation failed.",
773 "[] is too short");
774 }
775 // Invalid: test i2c_compare_bytes with property masks as empty array.
776 {
777 json configFile = i2cCompareBytesFile;
778 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] =
779 json::array();
780 EXPECT_JSON_INVALID(configFile, "Validation failed.",
781 "[] is too short");
782 }
783 // Invalid: test i2c_compare_bytes with property register wrong type.
784 {
785 json configFile = i2cCompareBytesFile;
786 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
787 1;
788 EXPECT_JSON_INVALID(configFile, "Validation failed.",
789 "1 is not of type u'string'");
790 }
791 // Invalid: test i2c_compare_bytes with property values wrong type.
792 {
793 json configFile = i2cCompareBytesFile;
794 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = 1;
795 EXPECT_JSON_INVALID(configFile, "Validation failed.",
796 "1 is not of type u'array'");
797 }
798 // Invalid: test i2c_compare_bytes with property masks wrong type.
799 {
800 json configFile = i2cCompareBytesFile;
801 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = 1;
802 EXPECT_JSON_INVALID(configFile, "Validation failed.",
803 "1 is not of type u'array'");
804 }
805 // Invalid: test i2c_compare_bytes with property register more than 2 hex
806 // digits.
807 {
808 json configFile = i2cCompareBytesFile;
809 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
810 "0x820";
811 EXPECT_JSON_INVALID(configFile, "Validation failed.",
812 "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
813 }
814 // Invalid: test i2c_compare_bytes with property values more than 2 hex
815 // digits.
816 {
817 json configFile = i2cCompareBytesFile;
818 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
819 "0x820";
820 EXPECT_JSON_INVALID(configFile, "Validation failed.",
821 "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
822 }
823 // Invalid: test i2c_compare_bytes with property masks more than 2 hex
824 // digits.
825 {
826 json configFile = i2cCompareBytesFile;
827 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
828 "0x820";
829 EXPECT_JSON_INVALID(configFile, "Validation failed.",
830 "u'0x820' does not match u'^0x[0-9A-Fa-f]{2}$'");
831 }
832 // Invalid: test i2c_compare_bytes with property register less than 2 hex
833 // digits.
834 {
835 json configFile = i2cCompareBytesFile;
836 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
837 "0x8";
838 EXPECT_JSON_INVALID(configFile, "Validation failed.",
839 "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
840 }
841 // Invalid: test i2c_compare_bytes with property values less than 2 hex
842 // digits.
843 {
844 json configFile = i2cCompareBytesFile;
845 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
846 "0x8";
847 EXPECT_JSON_INVALID(configFile, "Validation failed.",
848 "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
849 }
850 // Invalid: test i2c_compare_bytes with property masks less than 2 hex
851 // digits.
852 {
853 json configFile = i2cCompareBytesFile;
854 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
855 "0x8";
856 EXPECT_JSON_INVALID(configFile, "Validation failed.",
857 "u'0x8' does not match u'^0x[0-9A-Fa-f]{2}$'");
858 }
859 // Invalid: test i2c_compare_bytes with property register no leading prefix.
860 {
861 json configFile = i2cCompareBytesFile;
862 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
863 "82";
864 EXPECT_JSON_INVALID(configFile, "Validation failed.",
865 "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
866 }
867 // Invalid: test i2c_compare_bytes with property values no leading prefix.
868 {
869 json configFile = i2cCompareBytesFile;
870 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
871 "82";
872 EXPECT_JSON_INVALID(configFile, "Validation failed.",
873 "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
874 }
875 // Invalid: test i2c_compare_bytes with property masks no leading prefix.
876 {
877 json configFile = i2cCompareBytesFile;
878 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
879 "82";
880 EXPECT_JSON_INVALID(configFile, "Validation failed.",
881 "u'82' does not match u'^0x[0-9A-Fa-f]{2}$'");
882 }
883 // Invalid: test i2c_compare_bytes with property register invalid hex digit.
884 {
885 json configFile = i2cCompareBytesFile;
886 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
887 "0xG1";
888 EXPECT_JSON_INVALID(configFile, "Validation failed.",
889 "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
890 }
891 // Invalid: test i2c_compare_bytes with property values invalid hex digit.
892 {
893 json configFile = i2cCompareBytesFile;
894 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
895 "0xG1";
896 EXPECT_JSON_INVALID(configFile, "Validation failed.",
897 "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
898 }
899 // Invalid: test i2c_compare_bytes with property masks invalid hex digit.
900 {
901 json configFile = i2cCompareBytesFile;
902 configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
903 "0xG1";
904 EXPECT_JSON_INVALID(configFile, "Validation failed.",
905 "u'0xG1' does not match u'^0x[0-9A-Fa-f]{2}$'");
906 }
907}
Bob Kingead0b052020-01-21 11:29:03 +0800908TEST(ValidateRegulatorsConfigTest, If)
909{
910 json ifFile = validConfigFile;
911 ifFile["rules"][0]["actions"][1]["if"]["condition"]["run_rule"] =
912 "is_downlevel_regulator";
913 ifFile["rules"][0]["actions"][1]["if"]["then"][0]["run_rule"] =
914 "configure_downlevel_regulator";
915 ifFile["rules"][0]["actions"][1]["if"]["else"][0]["run_rule"] =
916 "configure_downlevel_regulator";
917 // Valid: test if.
918 {
919 json configFile = ifFile;
920 EXPECT_JSON_VALID(configFile);
921 }
922 // Valid: test if with required properties.
923 {
924 json configFile = ifFile;
925 configFile["rules"][0]["actions"][1]["if"].erase("else");
926 EXPECT_JSON_VALID(configFile);
927 }
928 // Invalid: test if with no property condition.
929 {
930 json configFile = ifFile;
931 configFile["rules"][0]["actions"][1]["if"].erase("condition");
932 EXPECT_JSON_INVALID(configFile, "Validation failed.",
933 "u'condition' is a required property");
934 }
935 // Invalid: test if with no property then.
936 {
937 json configFile = ifFile;
938 configFile["rules"][0]["actions"][1]["if"].erase("then");
939 EXPECT_JSON_INVALID(configFile, "Validation failed.",
940 "u'then' is a required property");
941 }
942 // Invalid: test if with property then empty array.
943 {
944 json configFile = ifFile;
945 configFile["rules"][0]["actions"][1]["if"]["then"] = json::array();
946 EXPECT_JSON_INVALID(configFile, "Validation failed.",
947 "[] is too short");
948 }
949 // Invalid: test if with property else empty array.
950 {
951 json configFile = ifFile;
952 configFile["rules"][0]["actions"][1]["if"]["else"] = json::array();
953 EXPECT_JSON_INVALID(configFile, "Validation failed.",
954 "[] is too short");
955 }
956 // Invalid: test if with property condition wrong type.
957 {
958 json configFile = ifFile;
959 configFile["rules"][0]["actions"][1]["if"]["condition"] = 1;
960 EXPECT_JSON_INVALID(configFile, "Validation failed.",
961 "1 is not of type u'object'");
962 }
963 // Invalid: test if with property then wrong type.
964 {
965 json configFile = ifFile;
966 configFile["rules"][0]["actions"][1]["if"]["then"] = 1;
967 EXPECT_JSON_INVALID(configFile, "Validation failed.",
968 "1 is not of type u'array'");
969 }
970 // Invalid: test if with property else wrong type.
971 {
972 json configFile = ifFile;
973 configFile["rules"][0]["actions"][1]["if"]["else"] = 1;
974 EXPECT_JSON_INVALID(configFile, "Validation failed.",
975 "1 is not of type u'array'");
976 }
977}
Bob Kingbfe9fe72020-01-21 11:29:57 +0800978TEST(ValidateRegulatorsConfigTest, Not)
979{
980 json notFile = validConfigFile;
981 notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["register"] =
982 "0xA0";
983 notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["value"] =
984 "0xFF";
985 // Valid: test not.
986 {
987 json configFile = notFile;
988 EXPECT_JSON_VALID(configFile);
989 }
990 // Invalid: test not with wrong type.
991 {
992 json configFile = notFile;
993 configFile["rules"][0]["actions"][1]["not"] = 1;
994 EXPECT_JSON_INVALID(configFile, "Validation failed.",
995 "1 is not of type u'object'");
996 }
997}
Bob Kingcfc29d02020-01-21 11:30:50 +0800998TEST(ValidateRegulatorsConfigTest, Or)
999{
1000 json orFile = validConfigFile;
1001 orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["register"] =
1002 "0xA0";
1003 orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["value"] =
1004 "0x00";
1005 orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["register"] =
1006 "0xA1";
1007 orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["value"] =
1008 "0x00";
1009 // Valid: test or.
1010 {
1011 json configFile = orFile;
1012 EXPECT_JSON_VALID(configFile);
1013 }
1014 // Invalid: test or with empty array.
1015 {
1016 json configFile = orFile;
1017 configFile["rules"][0]["actions"][1]["or"] = json::array();
1018 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1019 "[] is too short");
1020 }
1021 // Invalid: test or with wrong type.
1022 {
1023 json configFile = orFile;
1024 configFile["rules"][0]["actions"][1]["or"] = 1;
1025 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1026 "1 is not of type u'array'");
1027 }
1028}
Bob Kingd6618092020-01-21 11:31:46 +08001029TEST(ValidateRegulatorsConfigTest, PmbusReadSensor)
1030{
1031 json pmbusReadSensorFile = validConfigFile;
1032 pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1033 "vout";
1034 pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1035 ["command"] = "0x8B";
1036 pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1037 ["format"] = "linear_16";
1038 pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
1039 ["exponent"] = -8;
1040 // Valid: test pmbus_read_sensor.
1041 {
1042 json configFile = pmbusReadSensorFile;
1043 EXPECT_JSON_VALID(configFile);
1044 }
1045 // Valid: test pmbus_read_sensor with required properties.
1046 {
1047 json configFile = pmbusReadSensorFile;
1048 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1049 "exponent");
1050 EXPECT_JSON_VALID(configFile);
1051 }
1052 // Invalid: test pmbus_read_sensor with no type.
1053 {
1054 json configFile = pmbusReadSensorFile;
1055 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase("type");
1056 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1057 "u'type' is a required property");
1058 }
1059 // Invalid: test pmbus_read_sensor with no command.
1060 {
1061 json configFile = pmbusReadSensorFile;
1062 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1063 "command");
1064 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1065 "u'command' is a required property");
1066 }
1067 // Invalid: test pmbus_read_sensor with no format.
1068 {
1069 json configFile = pmbusReadSensorFile;
1070 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
1071 "format");
1072 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1073 "u'format' is a required property");
1074 }
1075 // Invalid: test pmbus_read_sensor with property type wrong type.
1076 {
1077 json configFile = pmbusReadSensorFile;
1078 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1079 true;
1080 EXPECT_JSON_INVALID(
1081 configFile, "Validation failed.",
1082 "True is not one of [u'iout', u'iout_peak', u'iout_valley', "
1083 "u'pout', u'temperature', u'temperature_peak', u'vout', "
1084 "u'vout_peak', u'vout_valley']");
1085 }
1086 // Invalid: test pmbus_read_sensor with property command wrong type.
1087 {
1088 json configFile = pmbusReadSensorFile;
1089 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1090 true;
1091 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1092 "True is not of type u'string'");
1093 }
1094 // Invalid: test pmbus_read_sensor with property format wrong type.
1095 {
1096 json configFile = pmbusReadSensorFile;
1097 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1098 true;
1099 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1100 "True is not one of [u'linear_11', u'linear_16']");
1101 }
1102 // Invalid: test pmbus_read_sensor with property exponent wrong type.
1103 {
1104 json configFile = pmbusReadSensorFile;
1105 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["exponent"] =
1106 true;
1107 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1108 "True is not of type u'integer'");
1109 }
1110 // Invalid: test pmbus_read_sensor with property type wrong format.
1111 {
1112 json configFile = pmbusReadSensorFile;
1113 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
1114 "foo";
1115 EXPECT_JSON_INVALID(
1116 configFile, "Validation failed.",
1117 "u'foo' is not one of [u'iout', u'iout_peak', u'iout_valley', "
1118 "u'pout', u'temperature', u'temperature_peak', u'vout', "
1119 "u'vout_peak', u'vout_valley']");
1120 }
1121 // Invalid: test pmbus_read_sensor with property command wrong format.
1122 {
1123 json configFile = pmbusReadSensorFile;
1124 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
1125 "0x8B0";
1126 EXPECT_JSON_INVALID(configFile, "Validation failed.",
1127 "u'0x8B0' does not match u'^0x[0-9a-fA-F]{2}$'");
1128 }
1129 // Invalid: test pmbus_read_sensor with property format wrong format.
1130 {
1131 json configFile = pmbusReadSensorFile;
1132 configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
1133 "foo";
1134 EXPECT_JSON_INVALID(
1135 configFile, "Validation failed.",
1136 "u'foo' is not one of [u'linear_11', u'linear_16']");
1137 }
1138}