1 /** 2 * Copyright © 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 "action.hpp" 17 #include "and_action.hpp" 18 #include "chassis.hpp" 19 #include "compare_presence_action.hpp" 20 #include "compare_vpd_action.hpp" 21 #include "config_file_parser.hpp" 22 #include "config_file_parser_error.hpp" 23 #include "configuration.hpp" 24 #include "device.hpp" 25 #include "i2c_capture_bytes_action.hpp" 26 #include "i2c_compare_bit_action.hpp" 27 #include "i2c_compare_byte_action.hpp" 28 #include "i2c_compare_bytes_action.hpp" 29 #include "i2c_interface.hpp" 30 #include "i2c_write_bit_action.hpp" 31 #include "i2c_write_byte_action.hpp" 32 #include "i2c_write_bytes_action.hpp" 33 #include "log_phase_fault_action.hpp" 34 #include "not_action.hpp" 35 #include "or_action.hpp" 36 #include "phase_fault.hpp" 37 #include "phase_fault_detection.hpp" 38 #include "pmbus_read_sensor_action.hpp" 39 #include "pmbus_utils.hpp" 40 #include "pmbus_write_vout_command_action.hpp" 41 #include "presence_detection.hpp" 42 #include "rail.hpp" 43 #include "rule.hpp" 44 #include "run_rule_action.hpp" 45 #include "sensor_monitoring.hpp" 46 #include "sensors.hpp" 47 #include "set_device_action.hpp" 48 #include "temporary_file.hpp" 49 50 #include <sys/stat.h> // for chmod() 51 52 #include <nlohmann/json.hpp> 53 54 #include <cstdint> 55 #include <cstring> 56 #include <exception> 57 #include <filesystem> 58 #include <fstream> 59 #include <memory> 60 #include <optional> 61 #include <stdexcept> 62 #include <string> 63 #include <tuple> 64 #include <vector> 65 66 #include <gtest/gtest.h> 67 68 using namespace phosphor::power::regulators; 69 using namespace phosphor::power::regulators::config_file_parser; 70 using namespace phosphor::power::regulators::config_file_parser::internal; 71 using ConfigFileParserError = phosphor::power::util::ConfigFileParserError; 72 using json = nlohmann::json; 73 using TemporaryFile = phosphor::power::util::TemporaryFile; 74 75 void writeConfigFile(const std::filesystem::path& pathName, 76 const std::string& contents) 77 { 78 std::ofstream file{pathName}; 79 file << contents; 80 } 81 82 void writeConfigFile(const std::filesystem::path& pathName, 83 const json& contents) 84 { 85 std::ofstream file{pathName}; 86 file << contents; 87 } 88 89 TEST(ConfigFileParserTests, Parse) 90 { 91 // Test where works 92 { 93 const json configFileContents = R"( 94 { 95 "rules": [ 96 { 97 "id": "set_voltage_rule1", 98 "actions": [ 99 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 100 ] 101 }, 102 { 103 "id": "set_voltage_rule2", 104 "actions": [ 105 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } } 106 ] 107 } 108 ], 109 "chassis": [ 110 { "number": 1, "inventory_path": "system/chassis1" }, 111 { "number": 2, "inventory_path": "system/chassis2" }, 112 { "number": 3, "inventory_path": "system/chassis3" } 113 ] 114 } 115 )"_json; 116 117 TemporaryFile configFile; 118 std::filesystem::path pathName{configFile.getPath()}; 119 writeConfigFile(pathName, configFileContents); 120 121 std::vector<std::unique_ptr<Rule>> rules{}; 122 std::vector<std::unique_ptr<Chassis>> chassis{}; 123 std::tie(rules, chassis) = parse(pathName); 124 125 EXPECT_EQ(rules.size(), 2); 126 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 127 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 128 129 EXPECT_EQ(chassis.size(), 3); 130 EXPECT_EQ(chassis[0]->getNumber(), 1); 131 EXPECT_EQ(chassis[0]->getInventoryPath(), 132 "/xyz/openbmc_project/inventory/system/chassis1"); 133 EXPECT_EQ(chassis[1]->getNumber(), 2); 134 EXPECT_EQ(chassis[1]->getInventoryPath(), 135 "/xyz/openbmc_project/inventory/system/chassis2"); 136 EXPECT_EQ(chassis[2]->getNumber(), 3); 137 EXPECT_EQ(chassis[2]->getInventoryPath(), 138 "/xyz/openbmc_project/inventory/system/chassis3"); 139 } 140 141 // Test where fails: File does not exist 142 try 143 { 144 std::filesystem::path pathName{"/tmp/non_existent_file"}; 145 parse(pathName); 146 ADD_FAILURE() << "Should not have reached this line."; 147 } 148 catch (const ConfigFileParserError& e) 149 { 150 // Expected exception; what() message will vary 151 } 152 153 // Test where fails: File is not readable 154 try 155 { 156 const json configFileContents = R"( 157 { 158 "chassis": [ 159 { "number": 1, "inventory_path": "system/chassis1" } 160 ] 161 } 162 )"_json; 163 164 TemporaryFile configFile; 165 std::filesystem::path pathName{configFile.getPath()}; 166 writeConfigFile(pathName, configFileContents); 167 168 chmod(pathName.c_str(), 0222); 169 170 parse(pathName); 171 ADD_FAILURE() << "Should not have reached this line."; 172 } 173 catch (const ConfigFileParserError& e) 174 { 175 // Expected exception; what() message will vary 176 } 177 178 // Test where fails: File is not valid JSON 179 try 180 { 181 const std::string configFileContents = "] foo ["; 182 183 TemporaryFile configFile; 184 std::filesystem::path pathName{configFile.getPath()}; 185 writeConfigFile(pathName, configFileContents); 186 187 parse(pathName); 188 ADD_FAILURE() << "Should not have reached this line."; 189 } 190 catch (const ConfigFileParserError& e) 191 { 192 // Expected exception; what() message will vary 193 } 194 195 // Test where fails: Error when parsing JSON elements 196 try 197 { 198 const json configFileContents = R"( { "foo": "bar" } )"_json; 199 200 TemporaryFile configFile; 201 std::filesystem::path pathName{configFile.getPath()}; 202 writeConfigFile(pathName, configFileContents); 203 204 parse(pathName); 205 ADD_FAILURE() << "Should not have reached this line."; 206 } 207 catch (const ConfigFileParserError& e) 208 { 209 // Expected exception; what() message will vary 210 } 211 } 212 213 TEST(ConfigFileParserTests, ParseAction) 214 { 215 // Test where works: comments property specified 216 { 217 const json element = R"( 218 { 219 "comments": [ "Set output voltage." ], 220 "pmbus_write_vout_command": { 221 "format": "linear" 222 } 223 } 224 )"_json; 225 std::unique_ptr<Action> action = parseAction(element); 226 EXPECT_NE(action.get(), nullptr); 227 } 228 229 // Test where works: comments property not specified 230 { 231 const json element = R"( 232 { 233 "pmbus_write_vout_command": { 234 "format": "linear" 235 } 236 } 237 )"_json; 238 std::unique_ptr<Action> action = parseAction(element); 239 EXPECT_NE(action.get(), nullptr); 240 } 241 242 // Test where works: and action type specified 243 { 244 const json element = R"( 245 { 246 "and": [ 247 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 248 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 249 ] 250 } 251 )"_json; 252 std::unique_ptr<Action> action = parseAction(element); 253 EXPECT_NE(action.get(), nullptr); 254 } 255 256 // Test where works: compare_presence action type specified 257 { 258 const json element = R"( 259 { 260 "compare_presence": 261 { 262 "fru": "system/chassis/motherboard/cpu3", 263 "value": true 264 } 265 } 266 )"_json; 267 std::unique_ptr<Action> action = parseAction(element); 268 EXPECT_NE(action.get(), nullptr); 269 } 270 271 // Test where works: compare_vpd action type specified 272 { 273 const json element = R"( 274 { 275 "compare_vpd": 276 { 277 "fru": "system/chassis/disk_backplane", 278 "keyword": "CCIN", 279 "value": "2D35" 280 } 281 } 282 )"_json; 283 std::unique_ptr<Action> action = parseAction(element); 284 EXPECT_NE(action.get(), nullptr); 285 } 286 287 // Test where works: i2c_capture_bytes action type specified 288 { 289 const json element = R"( 290 { 291 "i2c_capture_bytes": { 292 "register": "0xA0", 293 "count": 2 294 } 295 } 296 )"_json; 297 std::unique_ptr<Action> action = parseAction(element); 298 EXPECT_NE(action.get(), nullptr); 299 } 300 301 // Test where works: i2c_compare_bit action type specified 302 { 303 const json element = R"( 304 { 305 "i2c_compare_bit": { 306 "register": "0xA0", 307 "position": 3, 308 "value": 0 309 } 310 } 311 )"_json; 312 std::unique_ptr<Action> action = parseAction(element); 313 EXPECT_NE(action.get(), nullptr); 314 } 315 316 // Test where works: i2c_compare_byte action type specified 317 { 318 const json element = R"( 319 { 320 "i2c_compare_byte": { 321 "register": "0x0A", 322 "value": "0xCC" 323 } 324 } 325 )"_json; 326 std::unique_ptr<Action> action = parseAction(element); 327 EXPECT_NE(action.get(), nullptr); 328 } 329 330 // Test where works: i2c_compare_bytes action type specified 331 { 332 const json element = R"( 333 { 334 "i2c_compare_bytes": { 335 "register": "0x0A", 336 "values": [ "0xCC", "0xFF" ] 337 } 338 } 339 )"_json; 340 std::unique_ptr<Action> action = parseAction(element); 341 EXPECT_NE(action.get(), nullptr); 342 } 343 344 // Test where works: i2c_write_bit action type specified 345 { 346 const json element = R"( 347 { 348 "i2c_write_bit": { 349 "register": "0xA0", 350 "position": 3, 351 "value": 0 352 } 353 } 354 )"_json; 355 std::unique_ptr<Action> action = parseAction(element); 356 EXPECT_NE(action.get(), nullptr); 357 } 358 359 // Test where works: i2c_write_byte action type specified 360 { 361 const json element = R"( 362 { 363 "i2c_write_byte": { 364 "register": "0x0A", 365 "value": "0xCC" 366 } 367 } 368 )"_json; 369 std::unique_ptr<Action> action = parseAction(element); 370 EXPECT_NE(action.get(), nullptr); 371 } 372 373 // Test where works: i2c_write_bytes action type specified 374 { 375 const json element = R"( 376 { 377 "i2c_write_bytes": { 378 "register": "0x0A", 379 "values": [ "0xCC", "0xFF" ] 380 } 381 } 382 )"_json; 383 std::unique_ptr<Action> action = parseAction(element); 384 EXPECT_NE(action.get(), nullptr); 385 } 386 387 // Test where works: if action type specified 388 { 389 const json element = R"( 390 { 391 "if": 392 { 393 "condition": { "run_rule": "is_downlevel_regulator" }, 394 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 395 "else": [ { "run_rule": "configure_standard_regulator" } ] 396 } 397 } 398 )"_json; 399 std::unique_ptr<Action> action = parseAction(element); 400 EXPECT_NE(action.get(), nullptr); 401 } 402 403 // Test where works: log_phase_fault action type specified 404 { 405 const json element = R"( 406 { 407 "log_phase_fault": { 408 "type": "n+1" 409 } 410 } 411 )"_json; 412 std::unique_ptr<Action> action = parseAction(element); 413 EXPECT_NE(action.get(), nullptr); 414 } 415 416 // Test where works: not action type specified 417 { 418 const json element = R"( 419 { 420 "not": 421 { "i2c_compare_byte": { "register": "0xA0", "value": "0xFF" } } 422 } 423 )"_json; 424 std::unique_ptr<Action> action = parseAction(element); 425 EXPECT_NE(action.get(), nullptr); 426 } 427 428 // Test where works: or action type specified 429 { 430 const json element = R"( 431 { 432 "or": [ 433 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 434 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 435 ] 436 } 437 )"_json; 438 std::unique_ptr<Action> action = parseAction(element); 439 EXPECT_NE(action.get(), nullptr); 440 } 441 442 // Test where works: pmbus_read_sensor action type specified 443 { 444 const json element = R"( 445 { 446 "pmbus_read_sensor": { 447 "type": "iout", 448 "command": "0x8C", 449 "format": "linear_11" 450 } 451 } 452 )"_json; 453 std::unique_ptr<Action> action = parseAction(element); 454 EXPECT_NE(action.get(), nullptr); 455 } 456 457 // Test where works: pmbus_write_vout_command action type specified 458 { 459 const json element = R"( 460 { 461 "pmbus_write_vout_command": { 462 "format": "linear" 463 } 464 } 465 )"_json; 466 std::unique_ptr<Action> action = parseAction(element); 467 EXPECT_NE(action.get(), nullptr); 468 } 469 470 // Test where works: run_rule action type specified 471 { 472 const json element = R"( 473 { 474 "run_rule": "set_voltage_rule" 475 } 476 )"_json; 477 std::unique_ptr<Action> action = parseAction(element); 478 EXPECT_NE(action.get(), nullptr); 479 } 480 481 // Test where works: set_device action type specified 482 { 483 const json element = R"( 484 { 485 "set_device": "io_expander2" 486 } 487 )"_json; 488 std::unique_ptr<Action> action = parseAction(element); 489 EXPECT_NE(action.get(), nullptr); 490 } 491 492 // Test where fails: Element is not an object 493 try 494 { 495 const json element = R"( [ "0xFF", "0x01" ] )"_json; 496 parseAction(element); 497 ADD_FAILURE() << "Should not have reached this line."; 498 } 499 catch (const std::invalid_argument& e) 500 { 501 EXPECT_STREQ(e.what(), "Element is not an object"); 502 } 503 504 // Test where fails: No action type specified 505 try 506 { 507 const json element = R"( 508 { 509 "comments": [ "Set output voltage." ] 510 } 511 )"_json; 512 parseAction(element); 513 ADD_FAILURE() << "Should not have reached this line."; 514 } 515 catch (const std::invalid_argument& e) 516 { 517 EXPECT_STREQ(e.what(), "Required action type property missing"); 518 } 519 520 // Test where fails: Multiple action types specified 521 try 522 { 523 const json element = R"( 524 { 525 "pmbus_write_vout_command": { "format": "linear" }, 526 "run_rule": "set_voltage_rule" 527 } 528 )"_json; 529 parseAction(element); 530 ADD_FAILURE() << "Should not have reached this line."; 531 } 532 catch (const std::invalid_argument& e) 533 { 534 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 535 } 536 537 // Test where fails: Invalid property specified 538 try 539 { 540 const json element = R"( 541 { 542 "remarks": [ "Set output voltage." ], 543 "pmbus_write_vout_command": { 544 "format": "linear" 545 } 546 } 547 )"_json; 548 parseAction(element); 549 ADD_FAILURE() << "Should not have reached this line."; 550 } 551 catch (const std::invalid_argument& e) 552 { 553 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 554 } 555 } 556 557 TEST(ConfigFileParserTests, ParseActionArray) 558 { 559 // Test where works 560 { 561 const json element = R"( 562 [ 563 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 564 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 565 ] 566 )"_json; 567 std::vector<std::unique_ptr<Action>> actions = 568 parseActionArray(element); 569 EXPECT_EQ(actions.size(), 2); 570 } 571 572 // Test where fails: Element is not an array 573 try 574 { 575 const json element = R"( 576 { 577 "foo": "bar" 578 } 579 )"_json; 580 parseActionArray(element); 581 ADD_FAILURE() << "Should not have reached this line."; 582 } 583 catch (const std::invalid_argument& e) 584 { 585 EXPECT_STREQ(e.what(), "Element is not an array"); 586 } 587 } 588 589 TEST(ConfigFileParserTests, ParseAnd) 590 { 591 // Test where works: Element is an array with 2 actions 592 { 593 const json element = R"( 594 [ 595 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 596 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 597 ] 598 )"_json; 599 std::unique_ptr<AndAction> action = parseAnd(element); 600 EXPECT_EQ(action->getActions().size(), 2); 601 } 602 603 // Test where fails: Element is an array with 1 action 604 try 605 { 606 const json element = R"( 607 [ 608 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 609 ] 610 )"_json; 611 parseAnd(element); 612 ADD_FAILURE() << "Should not have reached this line."; 613 } 614 catch (const std::invalid_argument& e) 615 { 616 EXPECT_STREQ(e.what(), "Array must contain two or more actions"); 617 } 618 619 // Test where fails: Element is not an array 620 try 621 { 622 const json element = R"( 623 { 624 "foo": "bar" 625 } 626 )"_json; 627 parseAnd(element); 628 ADD_FAILURE() << "Should not have reached this line."; 629 } 630 catch (const std::invalid_argument& e) 631 { 632 EXPECT_STREQ(e.what(), "Element is not an array"); 633 } 634 } 635 636 TEST(ConfigFileParserTests, ParseChassis) 637 { 638 // Test where works: Only required properties specified 639 { 640 const json element = R"( 641 { 642 "number": 1, 643 "inventory_path": "system/chassis1" 644 } 645 )"_json; 646 std::unique_ptr<Chassis> chassis = parseChassis(element); 647 EXPECT_EQ(chassis->getNumber(), 1); 648 EXPECT_EQ(chassis->getInventoryPath(), 649 "/xyz/openbmc_project/inventory/system/chassis1"); 650 EXPECT_EQ(chassis->getDevices().size(), 0); 651 } 652 653 // Test where works: All properties specified 654 { 655 const json element = R"( 656 { 657 "comments": [ "comments property" ], 658 "number": 2, 659 "inventory_path": "system/chassis2", 660 "devices": [ 661 { 662 "id": "vdd_regulator", 663 "is_regulator": true, 664 "fru": "system/chassis/motherboard/regulator2", 665 "i2c_interface": 666 { 667 "bus": 1, 668 "address": "0x70" 669 } 670 } 671 ] 672 } 673 )"_json; 674 std::unique_ptr<Chassis> chassis = parseChassis(element); 675 EXPECT_EQ(chassis->getNumber(), 2); 676 EXPECT_EQ(chassis->getInventoryPath(), 677 "/xyz/openbmc_project/inventory/system/chassis2"); 678 EXPECT_EQ(chassis->getDevices().size(), 1); 679 EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator"); 680 } 681 682 // Test where fails: number value is invalid 683 try 684 { 685 const json element = R"( 686 { 687 "number": 0.5, 688 "inventory_path": "system/chassis" 689 } 690 )"_json; 691 parseChassis(element); 692 ADD_FAILURE() << "Should not have reached this line."; 693 } 694 catch (const std::invalid_argument& e) 695 { 696 EXPECT_STREQ(e.what(), "Element is not an integer"); 697 } 698 699 // Test where fails: inventory_path is invalid: Not a string 700 try 701 { 702 const json element = R"( 703 { 704 "number": 2, 705 "inventory_path": true 706 } 707 )"_json; 708 parseChassis(element); 709 ADD_FAILURE() << "Should not have reached this line."; 710 } 711 catch (const std::invalid_argument& e) 712 { 713 EXPECT_STREQ(e.what(), "Element is not a string"); 714 } 715 716 // Test where fails: inventory_path is invalid: Empty string 717 try 718 { 719 const json element = R"( 720 { 721 "number": 2, 722 "inventory_path": "" 723 } 724 )"_json; 725 parseChassis(element); 726 ADD_FAILURE() << "Should not have reached this line."; 727 } 728 catch (const std::invalid_argument& e) 729 { 730 EXPECT_STREQ(e.what(), "Element contains an empty string"); 731 } 732 733 // Test where fails: Invalid property specified 734 try 735 { 736 const json element = R"( 737 { 738 "number": 1, 739 "inventory_path": "system/chassis", 740 "foo": 2 741 } 742 )"_json; 743 parseChassis(element); 744 ADD_FAILURE() << "Should not have reached this line."; 745 } 746 catch (const std::invalid_argument& e) 747 { 748 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 749 } 750 751 // Test where fails: Required number property not specified 752 try 753 { 754 const json element = R"( 755 { 756 "inventory_path": "system/chassis" 757 } 758 )"_json; 759 parseChassis(element); 760 ADD_FAILURE() << "Should not have reached this line."; 761 } 762 catch (const std::invalid_argument& e) 763 { 764 EXPECT_STREQ(e.what(), "Required property missing: number"); 765 } 766 767 // Test where fails: Required inventory_path property not specified 768 try 769 { 770 const json element = R"( 771 { 772 "number": 1 773 } 774 )"_json; 775 parseChassis(element); 776 ADD_FAILURE() << "Should not have reached this line."; 777 } 778 catch (const std::invalid_argument& e) 779 { 780 EXPECT_STREQ(e.what(), "Required property missing: inventory_path"); 781 } 782 783 // Test where fails: Element is not an object 784 try 785 { 786 const json element = R"( [ "0xFF", "0x01" ] )"_json; 787 parseChassis(element); 788 ADD_FAILURE() << "Should not have reached this line."; 789 } 790 catch (const std::invalid_argument& e) 791 { 792 EXPECT_STREQ(e.what(), "Element is not an object"); 793 } 794 795 // Test where fails: number value is < 1 796 try 797 { 798 const json element = R"( 799 { 800 "number": 0, 801 "inventory_path": "system/chassis" 802 } 803 )"_json; 804 parseChassis(element); 805 ADD_FAILURE() << "Should not have reached this line."; 806 } 807 catch (const std::invalid_argument& e) 808 { 809 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0"); 810 } 811 812 // Test where fails: devices value is invalid 813 try 814 { 815 const json element = R"( 816 { 817 "number": 1, 818 "inventory_path": "system/chassis", 819 "devices": 2 820 } 821 )"_json; 822 parseChassis(element); 823 ADD_FAILURE() << "Should not have reached this line."; 824 } 825 catch (const std::invalid_argument& e) 826 { 827 EXPECT_STREQ(e.what(), "Element is not an array"); 828 } 829 } 830 831 TEST(ConfigFileParserTests, ParseChassisArray) 832 { 833 // Test where works 834 { 835 const json element = R"( 836 [ 837 { "number": 1, "inventory_path": "system/chassis1" }, 838 { "number": 2, "inventory_path": "system/chassis2" } 839 ] 840 )"_json; 841 std::vector<std::unique_ptr<Chassis>> chassis = 842 parseChassisArray(element); 843 EXPECT_EQ(chassis.size(), 2); 844 EXPECT_EQ(chassis[0]->getNumber(), 1); 845 EXPECT_EQ(chassis[0]->getInventoryPath(), 846 "/xyz/openbmc_project/inventory/system/chassis1"); 847 EXPECT_EQ(chassis[1]->getNumber(), 2); 848 EXPECT_EQ(chassis[1]->getInventoryPath(), 849 "/xyz/openbmc_project/inventory/system/chassis2"); 850 } 851 852 // Test where fails: Element is not an array 853 try 854 { 855 const json element = R"( 856 { 857 "foo": "bar" 858 } 859 )"_json; 860 parseChassisArray(element); 861 ADD_FAILURE() << "Should not have reached this line."; 862 } 863 catch (const std::invalid_argument& e) 864 { 865 EXPECT_STREQ(e.what(), "Element is not an array"); 866 } 867 } 868 869 TEST(ConfigFileParserTests, ParseComparePresence) 870 { 871 // Test where works 872 { 873 const json element = R"( 874 { 875 "fru": "system/chassis/motherboard/cpu3", 876 "value": true 877 } 878 )"_json; 879 std::unique_ptr<ComparePresenceAction> action = 880 parseComparePresence(element); 881 EXPECT_EQ( 882 action->getFRU(), 883 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3"); 884 EXPECT_EQ(action->getValue(), true); 885 } 886 887 // Test where fails: Element is not an object 888 try 889 { 890 const json element = R"( [ "0xFF", "0x01" ] )"_json; 891 parseComparePresence(element); 892 ADD_FAILURE() << "Should not have reached this line."; 893 } 894 catch (const std::invalid_argument& e) 895 { 896 EXPECT_STREQ(e.what(), "Element is not an object"); 897 } 898 899 // Test where fails: Invalid property specified 900 try 901 { 902 const json element = R"( 903 { 904 "fru": "system/chassis/motherboard/cpu3", 905 "value": true, 906 "foo" : true 907 } 908 )"_json; 909 parseComparePresence(element); 910 ADD_FAILURE() << "Should not have reached this line."; 911 } 912 catch (const std::invalid_argument& e) 913 { 914 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 915 } 916 917 // Test where fails: Required fru property not specified 918 try 919 { 920 const json element = R"( 921 { 922 "value": true 923 } 924 )"_json; 925 parseComparePresence(element); 926 ADD_FAILURE() << "Should not have reached this line."; 927 } 928 catch (const std::invalid_argument& e) 929 { 930 EXPECT_STREQ(e.what(), "Required property missing: fru"); 931 } 932 933 // Test where fails: Required value property not specified 934 try 935 { 936 const json element = R"( 937 { 938 "fru": "system/chassis/motherboard/cpu3" 939 } 940 )"_json; 941 parseComparePresence(element); 942 ADD_FAILURE() << "Should not have reached this line."; 943 } 944 catch (const std::invalid_argument& e) 945 { 946 EXPECT_STREQ(e.what(), "Required property missing: value"); 947 } 948 949 // Test where fails: fru value is invalid 950 try 951 { 952 const json element = R"( 953 { 954 "fru": 1, 955 "value": true 956 } 957 )"_json; 958 parseComparePresence(element); 959 ADD_FAILURE() << "Should not have reached this line."; 960 } 961 catch (const std::invalid_argument& e) 962 { 963 EXPECT_STREQ(e.what(), "Element is not a string"); 964 } 965 966 // Test where fails: value value is invalid 967 try 968 { 969 const json element = R"( 970 { 971 "fru": "system/chassis/motherboard/cpu3", 972 "value": 1 973 } 974 )"_json; 975 parseComparePresence(element); 976 ADD_FAILURE() << "Should not have reached this line."; 977 } 978 catch (const std::invalid_argument& e) 979 { 980 EXPECT_STREQ(e.what(), "Element is not a boolean"); 981 } 982 } 983 984 TEST(ConfigFileParserTests, ParseCompareVPD) 985 { 986 // Test where works: value property: Not empty 987 { 988 const json element = R"( 989 { 990 "fru": "system/chassis/disk_backplane", 991 "keyword": "CCIN", 992 "value": "2D35" 993 } 994 )"_json; 995 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 996 EXPECT_EQ( 997 action->getFRU(), 998 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 999 EXPECT_EQ(action->getKeyword(), "CCIN"); 1000 EXPECT_EQ(action->getValue(), 1001 (std::vector<uint8_t>{0x32, 0x44, 0x33, 0x35})); 1002 } 1003 1004 // Test where works: value property: Empty 1005 { 1006 const json element = R"( 1007 { 1008 "fru": "system/chassis/disk_backplane", 1009 "keyword": "CCIN", 1010 "value": "" 1011 } 1012 )"_json; 1013 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1014 EXPECT_EQ( 1015 action->getFRU(), 1016 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1017 EXPECT_EQ(action->getKeyword(), "CCIN"); 1018 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{})); 1019 } 1020 1021 // Test where works: byte_values property: Not empty 1022 { 1023 const json element = R"( 1024 { 1025 "fru": "system/chassis/disk_backplane", 1026 "keyword": "CCIN", 1027 "byte_values": ["0x11", "0x22", "0x33"] 1028 } 1029 )"_json; 1030 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1031 EXPECT_EQ( 1032 action->getFRU(), 1033 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1034 EXPECT_EQ(action->getKeyword(), "CCIN"); 1035 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{0x11, 0x22, 0x33})); 1036 } 1037 1038 // Test where works: byte_values property: Empty 1039 { 1040 const json element = R"( 1041 { 1042 "fru": "system/chassis/disk_backplane", 1043 "keyword": "CCIN", 1044 "byte_values": [] 1045 } 1046 )"_json; 1047 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1048 EXPECT_EQ( 1049 action->getFRU(), 1050 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1051 EXPECT_EQ(action->getKeyword(), "CCIN"); 1052 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{})); 1053 } 1054 1055 // Test where fails: Element is not an object 1056 try 1057 { 1058 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1059 parseCompareVPD(element); 1060 ADD_FAILURE() << "Should not have reached this line."; 1061 } 1062 catch (const std::invalid_argument& e) 1063 { 1064 EXPECT_STREQ(e.what(), "Element is not an object"); 1065 } 1066 1067 // Test where fails: Invalid property specified 1068 try 1069 { 1070 const json element = R"( 1071 { 1072 "fru": "system/chassis/disk_backplane", 1073 "keyword": "CCIN", 1074 "value": "2D35", 1075 "foo" : true 1076 } 1077 )"_json; 1078 parseCompareVPD(element); 1079 ADD_FAILURE() << "Should not have reached this line."; 1080 } 1081 catch (const std::invalid_argument& e) 1082 { 1083 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1084 } 1085 1086 // Test where fails: Required fru property not specified 1087 try 1088 { 1089 const json element = R"( 1090 { 1091 "keyword": "CCIN", 1092 "value": "2D35" 1093 } 1094 )"_json; 1095 parseCompareVPD(element); 1096 ADD_FAILURE() << "Should not have reached this line."; 1097 } 1098 catch (const std::invalid_argument& e) 1099 { 1100 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1101 } 1102 1103 // Test where fails: Required keyword property not specified 1104 try 1105 { 1106 const json element = R"( 1107 { 1108 "fru": "system/chassis/disk_backplane", 1109 "value": "2D35" 1110 } 1111 )"_json; 1112 parseCompareVPD(element); 1113 ADD_FAILURE() << "Should not have reached this line."; 1114 } 1115 catch (const std::invalid_argument& e) 1116 { 1117 EXPECT_STREQ(e.what(), "Required property missing: keyword"); 1118 } 1119 1120 // Test where fails: Required value property not specified 1121 try 1122 { 1123 const json element = R"( 1124 { 1125 "fru": "system/chassis/disk_backplane", 1126 "keyword": "CCIN" 1127 } 1128 )"_json; 1129 parseCompareVPD(element); 1130 ADD_FAILURE() << "Should not have reached this line."; 1131 } 1132 catch (const std::invalid_argument& e) 1133 { 1134 EXPECT_STREQ(e.what(), "Invalid property: Must contain " 1135 "either value or byte_values"); 1136 } 1137 1138 // Test where fails: both value and byte_values specified 1139 try 1140 { 1141 const json element = R"( 1142 { 1143 "fru": "system/chassis/disk_backplane", 1144 "keyword": "CCIN", 1145 "value": "2D35", 1146 "byte_values": [ "0x01", "0x02" ] 1147 } 1148 )"_json; 1149 parseCompareVPD(element); 1150 ADD_FAILURE() << "Should not have reached this line."; 1151 } 1152 catch (const std::invalid_argument& e) 1153 { 1154 EXPECT_STREQ(e.what(), "Invalid property: Must contain " 1155 "either value or byte_values"); 1156 } 1157 1158 // Test where fails: fru value is invalid 1159 try 1160 { 1161 const json element = R"( 1162 { 1163 "fru": 1, 1164 "keyword": "CCIN", 1165 "value": "2D35" 1166 } 1167 )"_json; 1168 parseCompareVPD(element); 1169 ADD_FAILURE() << "Should not have reached this line."; 1170 } 1171 catch (const std::invalid_argument& e) 1172 { 1173 EXPECT_STREQ(e.what(), "Element is not a string"); 1174 } 1175 1176 // Test where fails: keyword value is invalid 1177 try 1178 { 1179 const json element = R"( 1180 { 1181 "fru": "system/chassis/disk_backplane", 1182 "keyword": 1, 1183 "value": "2D35" 1184 } 1185 )"_json; 1186 parseCompareVPD(element); 1187 ADD_FAILURE() << "Should not have reached this line."; 1188 } 1189 catch (const std::invalid_argument& e) 1190 { 1191 EXPECT_STREQ(e.what(), "Element is not a string"); 1192 } 1193 1194 // Test where fails: value value is invalid 1195 try 1196 { 1197 const json element = R"( 1198 { 1199 "fru": "system/chassis/disk_backplane", 1200 "keyword": "CCIN", 1201 "value": 1 1202 } 1203 )"_json; 1204 parseCompareVPD(element); 1205 ADD_FAILURE() << "Should not have reached this line."; 1206 } 1207 catch (const std::invalid_argument& e) 1208 { 1209 EXPECT_STREQ(e.what(), "Element is not a string"); 1210 } 1211 1212 // Test where fails: byte_values is wrong format 1213 try 1214 { 1215 const json element = R"( 1216 { 1217 "fru": "system/chassis/disk_backplane", 1218 "keyword": "CCIN", 1219 "byte_values": [1, 2, 3] 1220 } 1221 )"_json; 1222 parseCompareVPD(element); 1223 ADD_FAILURE() << "Should not have reached this line."; 1224 } 1225 catch (const std::invalid_argument& e) 1226 { 1227 EXPECT_STREQ(e.what(), "Element is not a string"); 1228 } 1229 } 1230 1231 TEST(ConfigFileParserTests, ParseConfiguration) 1232 { 1233 // Test where works: actions required property specified 1234 { 1235 const json element = R"( 1236 { 1237 "actions": [ 1238 { 1239 "pmbus_write_vout_command": { 1240 "format": "linear" 1241 } 1242 } 1243 ] 1244 } 1245 )"_json; 1246 std::unique_ptr<Configuration> configuration = 1247 parseConfiguration(element); 1248 EXPECT_EQ(configuration->getActions().size(), 1); 1249 EXPECT_EQ(configuration->getVolts().has_value(), false); 1250 } 1251 1252 // Test where works: volts and actions properties specified 1253 { 1254 const json element = R"( 1255 { 1256 "comments": [ "comments property" ], 1257 "volts": 1.03, 1258 "actions": [ 1259 { "pmbus_write_vout_command": { "format": "linear" } }, 1260 { "run_rule": "set_voltage_rule" } 1261 ] 1262 } 1263 )"_json; 1264 std::unique_ptr<Configuration> configuration = 1265 parseConfiguration(element); 1266 EXPECT_EQ(configuration->getVolts().has_value(), true); 1267 EXPECT_EQ(configuration->getVolts().value(), 1.03); 1268 EXPECT_EQ(configuration->getActions().size(), 2); 1269 } 1270 1271 // Test where works: volts and rule_id properties specified 1272 { 1273 const json element = R"( 1274 { 1275 "volts": 1.05, 1276 "rule_id": "set_voltage_rule" 1277 } 1278 )"_json; 1279 std::unique_ptr<Configuration> configuration = 1280 parseConfiguration(element); 1281 EXPECT_EQ(configuration->getVolts().has_value(), true); 1282 EXPECT_EQ(configuration->getVolts().value(), 1.05); 1283 EXPECT_EQ(configuration->getActions().size(), 1); 1284 } 1285 1286 // Test where fails: volts value is invalid 1287 try 1288 { 1289 const json element = R"( 1290 { 1291 "volts": "foo", 1292 "actions": [ 1293 { 1294 "pmbus_write_vout_command": { 1295 "format": "linear" 1296 } 1297 } 1298 ] 1299 } 1300 )"_json; 1301 parseConfiguration(element); 1302 ADD_FAILURE() << "Should not have reached this line."; 1303 } 1304 catch (const std::invalid_argument& e) 1305 { 1306 EXPECT_STREQ(e.what(), "Element is not a double"); 1307 } 1308 1309 // Test where fails: actions object is invalid 1310 try 1311 { 1312 const json element = R"( 1313 { 1314 "volts": 1.03, 1315 "actions": 1 1316 } 1317 )"_json; 1318 parseConfiguration(element); 1319 ADD_FAILURE() << "Should not have reached this line."; 1320 } 1321 catch (const std::invalid_argument& e) 1322 { 1323 EXPECT_STREQ(e.what(), "Element is not an array"); 1324 } 1325 1326 // Test where fails: rule_id value is invalid 1327 try 1328 { 1329 const json element = R"( 1330 { 1331 "volts": 1.05, 1332 "rule_id": 1 1333 } 1334 )"_json; 1335 parseConfiguration(element); 1336 ADD_FAILURE() << "Should not have reached this line."; 1337 } 1338 catch (const std::invalid_argument& e) 1339 { 1340 EXPECT_STREQ(e.what(), "Element is not a string"); 1341 } 1342 1343 // Test where fails: Required actions or rule_id property not specified 1344 try 1345 { 1346 const json element = R"( 1347 { 1348 "volts": 1.03 1349 } 1350 )"_json; 1351 parseConfiguration(element); 1352 ADD_FAILURE() << "Should not have reached this line."; 1353 } 1354 catch (const std::invalid_argument& e) 1355 { 1356 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 1357 "either rule_id or actions"); 1358 } 1359 1360 // Test where fails: Required actions or rule_id property both specified 1361 try 1362 { 1363 const json element = R"( 1364 { 1365 "volts": 1.03, 1366 "rule_id": "set_voltage_rule", 1367 "actions": [ 1368 { 1369 "pmbus_write_vout_command": { 1370 "format": "linear" 1371 } 1372 } 1373 ] 1374 } 1375 )"_json; 1376 parseConfiguration(element); 1377 ADD_FAILURE() << "Should not have reached this line."; 1378 } 1379 catch (const std::invalid_argument& e) 1380 { 1381 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 1382 "either rule_id or actions"); 1383 } 1384 1385 // Test where fails: Element is not an object 1386 try 1387 { 1388 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1389 parseConfiguration(element); 1390 ADD_FAILURE() << "Should not have reached this line."; 1391 } 1392 catch (const std::invalid_argument& e) 1393 { 1394 EXPECT_STREQ(e.what(), "Element is not an object"); 1395 } 1396 1397 // Test where fails: Invalid property specified 1398 try 1399 { 1400 const json element = R"( 1401 { 1402 "volts": 1.03, 1403 "rule_id": "set_voltage_rule", 1404 "foo": 1 1405 } 1406 )"_json; 1407 parseConfiguration(element); 1408 ADD_FAILURE() << "Should not have reached this line."; 1409 } 1410 catch (const std::invalid_argument& e) 1411 { 1412 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1413 } 1414 } 1415 1416 TEST(ConfigFileParserTests, ParseDevice) 1417 { 1418 // Test where works: Only required properties specified 1419 { 1420 const json element = R"( 1421 { 1422 "id": "vdd_regulator", 1423 "is_regulator": true, 1424 "fru": "system/chassis/motherboard/regulator2", 1425 "i2c_interface": { "bus": 1, "address": "0x70" } 1426 } 1427 )"_json; 1428 std::unique_ptr<Device> device = parseDevice(element); 1429 EXPECT_EQ(device->getID(), "vdd_regulator"); 1430 EXPECT_EQ(device->isRegulator(), true); 1431 EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/" 1432 "chassis/motherboard/regulator2"); 1433 EXPECT_NE(&(device->getI2CInterface()), nullptr); 1434 EXPECT_EQ(device->getPresenceDetection(), nullptr); 1435 EXPECT_EQ(device->getConfiguration(), nullptr); 1436 EXPECT_EQ(device->getPhaseFaultDetection(), nullptr); 1437 EXPECT_EQ(device->getRails().size(), 0); 1438 } 1439 1440 // Test where works: All properties specified 1441 { 1442 const json element = R"( 1443 { 1444 "comments": [ "VDD Regulator" ], 1445 "id": "vdd_regulator", 1446 "is_regulator": true, 1447 "fru": "system/chassis/motherboard/regulator2", 1448 "i2c_interface": 1449 { 1450 "bus": 1, 1451 "address": "0x70" 1452 }, 1453 "presence_detection": 1454 { 1455 "rule_id": "is_foobar_backplane_installed_rule" 1456 }, 1457 "configuration": 1458 { 1459 "rule_id": "configure_ir35221_rule" 1460 }, 1461 "phase_fault_detection": 1462 { 1463 "rule_id": "detect_phase_fault_rule" 1464 }, 1465 "rails": 1466 [ 1467 { 1468 "id": "vdd" 1469 } 1470 ] 1471 } 1472 )"_json; 1473 std::unique_ptr<Device> device = parseDevice(element); 1474 EXPECT_EQ(device->getID(), "vdd_regulator"); 1475 EXPECT_EQ(device->isRegulator(), true); 1476 EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/" 1477 "chassis/motherboard/regulator2"); 1478 EXPECT_NE(&(device->getI2CInterface()), nullptr); 1479 EXPECT_NE(device->getPresenceDetection(), nullptr); 1480 EXPECT_NE(device->getConfiguration(), nullptr); 1481 EXPECT_NE(device->getPhaseFaultDetection(), nullptr); 1482 EXPECT_EQ(device->getRails().size(), 1); 1483 } 1484 1485 // Test where fails: phase_fault_detection property exists and is_regulator 1486 // is false 1487 try 1488 { 1489 const json element = R"( 1490 { 1491 "id": "vdd_regulator", 1492 "is_regulator": false, 1493 "fru": "system/chassis/motherboard/regulator2", 1494 "i2c_interface": 1495 { 1496 "bus": 1, 1497 "address": "0x70" 1498 }, 1499 "phase_fault_detection": 1500 { 1501 "rule_id": "detect_phase_fault_rule" 1502 } 1503 } 1504 )"_json; 1505 parseDevice(element); 1506 ADD_FAILURE() << "Should not have reached this line."; 1507 } 1508 catch (const std::invalid_argument& e) 1509 { 1510 EXPECT_STREQ(e.what(), "Invalid phase_fault_detection property when " 1511 "is_regulator is false"); 1512 } 1513 1514 // Test where fails: rails property exists and is_regulator is false 1515 try 1516 { 1517 const json element = R"( 1518 { 1519 "id": "vdd_regulator", 1520 "is_regulator": false, 1521 "fru": "system/chassis/motherboard/regulator2", 1522 "i2c_interface": 1523 { 1524 "bus": 1, 1525 "address": "0x70" 1526 }, 1527 "configuration": 1528 { 1529 "rule_id": "configure_ir35221_rule" 1530 }, 1531 "rails": 1532 [ 1533 { 1534 "id": "vdd" 1535 } 1536 ] 1537 } 1538 )"_json; 1539 parseDevice(element); 1540 ADD_FAILURE() << "Should not have reached this line."; 1541 } 1542 catch (const std::invalid_argument& e) 1543 { 1544 EXPECT_STREQ(e.what(), 1545 "Invalid rails property when is_regulator is false"); 1546 } 1547 1548 // Test where fails: id value is invalid 1549 try 1550 { 1551 const json element = R"( 1552 { 1553 "id": 3, 1554 "is_regulator": true, 1555 "fru": "system/chassis/motherboard/regulator2", 1556 "i2c_interface": 1557 { 1558 "bus": 1, 1559 "address": "0x70" 1560 } 1561 } 1562 )"_json; 1563 parseDevice(element); 1564 ADD_FAILURE() << "Should not have reached this line."; 1565 } 1566 catch (const std::invalid_argument& e) 1567 { 1568 EXPECT_STREQ(e.what(), "Element is not a string"); 1569 } 1570 1571 // Test where fails: is_regulator value is invalid 1572 try 1573 { 1574 const json element = R"( 1575 { 1576 "id": "vdd_regulator", 1577 "is_regulator": 3, 1578 "fru": "system/chassis/motherboard/regulator2", 1579 "i2c_interface": 1580 { 1581 "bus": 1, 1582 "address": "0x70" 1583 } 1584 } 1585 )"_json; 1586 parseDevice(element); 1587 ADD_FAILURE() << "Should not have reached this line."; 1588 } 1589 catch (const std::invalid_argument& e) 1590 { 1591 EXPECT_STREQ(e.what(), "Element is not a boolean"); 1592 } 1593 1594 // Test where fails: fru value is invalid 1595 try 1596 { 1597 const json element = R"( 1598 { 1599 "id": "vdd_regulator", 1600 "is_regulator": true, 1601 "fru": 2, 1602 "i2c_interface": 1603 { 1604 "bus": 1, 1605 "address": "0x70" 1606 } 1607 } 1608 )"_json; 1609 parseDevice(element); 1610 ADD_FAILURE() << "Should not have reached this line."; 1611 } 1612 catch (const std::invalid_argument& e) 1613 { 1614 EXPECT_STREQ(e.what(), "Element is not a string"); 1615 } 1616 1617 // Test where fails: i2c_interface value is invalid 1618 try 1619 { 1620 const json element = R"( 1621 { 1622 "id": "vdd_regulator", 1623 "is_regulator": true, 1624 "fru": "system/chassis/motherboard/regulator2", 1625 "i2c_interface": 3 1626 } 1627 )"_json; 1628 parseDevice(element); 1629 ADD_FAILURE() << "Should not have reached this line."; 1630 } 1631 catch (const std::invalid_argument& e) 1632 { 1633 EXPECT_STREQ(e.what(), "Element is not an object"); 1634 } 1635 1636 // Test where fails: Required id property not specified 1637 try 1638 { 1639 const json element = R"( 1640 { 1641 "is_regulator": true, 1642 "fru": "system/chassis/motherboard/regulator2", 1643 "i2c_interface": 1644 { 1645 "bus": 1, 1646 "address": "0x70" 1647 } 1648 } 1649 )"_json; 1650 parseDevice(element); 1651 ADD_FAILURE() << "Should not have reached this line."; 1652 } 1653 catch (const std::invalid_argument& e) 1654 { 1655 EXPECT_STREQ(e.what(), "Required property missing: id"); 1656 } 1657 1658 // Test where fails: Required is_regulator property not specified 1659 try 1660 { 1661 const json element = R"( 1662 { 1663 "id": "vdd_regulator", 1664 "fru": "system/chassis/motherboard/regulator2", 1665 "i2c_interface": 1666 { 1667 "bus": 1, 1668 "address": "0x70" 1669 } 1670 } 1671 )"_json; 1672 parseDevice(element); 1673 ADD_FAILURE() << "Should not have reached this line."; 1674 } 1675 catch (const std::invalid_argument& e) 1676 { 1677 EXPECT_STREQ(e.what(), "Required property missing: is_regulator"); 1678 } 1679 1680 // Test where fails: Required fru property not specified 1681 try 1682 { 1683 const json element = R"( 1684 { 1685 "id": "vdd_regulator", 1686 "is_regulator": true, 1687 "i2c_interface": 1688 { 1689 "bus": 1, 1690 "address": "0x70" 1691 } 1692 } 1693 )"_json; 1694 parseDevice(element); 1695 ADD_FAILURE() << "Should not have reached this line."; 1696 } 1697 catch (const std::invalid_argument& e) 1698 { 1699 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1700 } 1701 1702 // Test where fails: Required i2c_interface property not specified 1703 try 1704 { 1705 const json element = R"( 1706 { 1707 "id": "vdd_regulator", 1708 "is_regulator": true, 1709 "fru": "system/chassis/motherboard/regulator2" 1710 } 1711 )"_json; 1712 parseDevice(element); 1713 ADD_FAILURE() << "Should not have reached this line."; 1714 } 1715 catch (const std::invalid_argument& e) 1716 { 1717 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface"); 1718 } 1719 1720 // Test where fails: Element is not an object 1721 try 1722 { 1723 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1724 parseDevice(element); 1725 ADD_FAILURE() << "Should not have reached this line."; 1726 } 1727 catch (const std::invalid_argument& e) 1728 { 1729 EXPECT_STREQ(e.what(), "Element is not an object"); 1730 } 1731 1732 // Test where fails: Invalid property specified 1733 try 1734 { 1735 const json element = R"( 1736 { 1737 "id": "vdd_regulator", 1738 "is_regulator": true, 1739 "fru": "system/chassis/motherboard/regulator2", 1740 "i2c_interface": { "bus": 1, "address": "0x70" }, 1741 "foo" : true 1742 } 1743 )"_json; 1744 parseDevice(element); 1745 ADD_FAILURE() << "Should not have reached this line."; 1746 } 1747 catch (const std::invalid_argument& e) 1748 { 1749 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1750 } 1751 } 1752 1753 TEST(ConfigFileParserTests, ParseDeviceArray) 1754 { 1755 // Test where works 1756 { 1757 const json element = R"( 1758 [ 1759 { 1760 "id": "vdd_regulator", 1761 "is_regulator": true, 1762 "fru": "system/chassis/motherboard/regulator2", 1763 "i2c_interface": { "bus": 1, "address": "0x70" } 1764 }, 1765 { 1766 "id": "vio_regulator", 1767 "is_regulator": true, 1768 "fru": "system/chassis/motherboard/regulator2", 1769 "i2c_interface": { "bus": 1, "address": "0x71" } 1770 } 1771 ] 1772 )"_json; 1773 std::vector<std::unique_ptr<Device>> devices = 1774 parseDeviceArray(element); 1775 EXPECT_EQ(devices.size(), 2); 1776 EXPECT_EQ(devices[0]->getID(), "vdd_regulator"); 1777 EXPECT_EQ(devices[1]->getID(), "vio_regulator"); 1778 } 1779 1780 // Test where fails: Element is not an array 1781 try 1782 { 1783 const json element = R"( 1784 { 1785 "foo": "bar" 1786 } 1787 )"_json; 1788 parseDeviceArray(element); 1789 ADD_FAILURE() << "Should not have reached this line."; 1790 } 1791 catch (const std::invalid_argument& e) 1792 { 1793 EXPECT_STREQ(e.what(), "Element is not an array"); 1794 } 1795 } 1796 1797 TEST(ConfigFileParserTests, ParseI2CCaptureBytes) 1798 { 1799 // Test where works 1800 { 1801 const json element = R"( 1802 { 1803 "register": "0xA0", 1804 "count": 2 1805 } 1806 )"_json; 1807 std::unique_ptr<I2CCaptureBytesAction> action = 1808 parseI2CCaptureBytes(element); 1809 EXPECT_EQ(action->getRegister(), 0xA0); 1810 EXPECT_EQ(action->getCount(), 2); 1811 } 1812 1813 // Test where fails: Element is not an object 1814 try 1815 { 1816 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1817 parseI2CCaptureBytes(element); 1818 ADD_FAILURE() << "Should not have reached this line."; 1819 } 1820 catch (const std::invalid_argument& e) 1821 { 1822 EXPECT_STREQ(e.what(), "Element is not an object"); 1823 } 1824 1825 // Test where fails: register value is invalid 1826 try 1827 { 1828 const json element = R"( 1829 { 1830 "register": "0x0Z", 1831 "count": 2 1832 } 1833 )"_json; 1834 parseI2CCaptureBytes(element); 1835 ADD_FAILURE() << "Should not have reached this line."; 1836 } 1837 catch (const std::invalid_argument& e) 1838 { 1839 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1840 } 1841 1842 // Test where fails: count value is invalid 1843 try 1844 { 1845 const json element = R"( 1846 { 1847 "register": "0xA0", 1848 "count": 0 1849 } 1850 )"_json; 1851 parseI2CCaptureBytes(element); 1852 ADD_FAILURE() << "Should not have reached this line."; 1853 } 1854 catch (const std::invalid_argument& e) 1855 { 1856 EXPECT_STREQ(e.what(), "Invalid byte count: Must be > 0"); 1857 } 1858 1859 // Test where fails: Required register property not specified 1860 try 1861 { 1862 const json element = R"( 1863 { 1864 "count": 2 1865 } 1866 )"_json; 1867 parseI2CCaptureBytes(element); 1868 ADD_FAILURE() << "Should not have reached this line."; 1869 } 1870 catch (const std::invalid_argument& e) 1871 { 1872 EXPECT_STREQ(e.what(), "Required property missing: register"); 1873 } 1874 1875 // Test where fails: Required count property not specified 1876 try 1877 { 1878 const json element = R"( 1879 { 1880 "register": "0xA0" 1881 } 1882 )"_json; 1883 parseI2CCaptureBytes(element); 1884 ADD_FAILURE() << "Should not have reached this line."; 1885 } 1886 catch (const std::invalid_argument& e) 1887 { 1888 EXPECT_STREQ(e.what(), "Required property missing: count"); 1889 } 1890 1891 // Test where fails: Invalid property specified 1892 try 1893 { 1894 const json element = R"( 1895 { 1896 "register": "0xA0", 1897 "count": 2, 1898 "foo": 3 1899 } 1900 )"_json; 1901 parseI2CCaptureBytes(element); 1902 ADD_FAILURE() << "Should not have reached this line."; 1903 } 1904 catch (const std::invalid_argument& e) 1905 { 1906 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1907 } 1908 } 1909 1910 TEST(ConfigFileParserTests, ParseI2CCompareBit) 1911 { 1912 // Test where works 1913 { 1914 const json element = R"( 1915 { 1916 "register": "0xA0", 1917 "position": 3, 1918 "value": 0 1919 } 1920 )"_json; 1921 std::unique_ptr<I2CCompareBitAction> action = 1922 parseI2CCompareBit(element); 1923 EXPECT_EQ(action->getRegister(), 0xA0); 1924 EXPECT_EQ(action->getPosition(), 3); 1925 EXPECT_EQ(action->getValue(), 0); 1926 } 1927 1928 // Test where fails: Invalid property specified 1929 try 1930 { 1931 const json element = R"( 1932 { 1933 "register": "0xA0", 1934 "position": 3, 1935 "value": 0, 1936 "foo": 3 1937 } 1938 )"_json; 1939 parseI2CCompareBit(element); 1940 ADD_FAILURE() << "Should not have reached this line."; 1941 } 1942 catch (const std::invalid_argument& e) 1943 { 1944 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1945 } 1946 1947 // Test where fails: Element is not an object 1948 try 1949 { 1950 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1951 parseI2CCompareBit(element); 1952 ADD_FAILURE() << "Should not have reached this line."; 1953 } 1954 catch (const std::invalid_argument& e) 1955 { 1956 EXPECT_STREQ(e.what(), "Element is not an object"); 1957 } 1958 1959 // Test where fails: register value is invalid 1960 try 1961 { 1962 const json element = R"( 1963 { 1964 "register": "0xAG", 1965 "position": 3, 1966 "value": 0 1967 } 1968 )"_json; 1969 parseI2CCompareBit(element); 1970 ADD_FAILURE() << "Should not have reached this line."; 1971 } 1972 catch (const std::invalid_argument& e) 1973 { 1974 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1975 } 1976 1977 // Test where fails: position value is invalid 1978 try 1979 { 1980 const json element = R"( 1981 { 1982 "register": "0xA0", 1983 "position": 8, 1984 "value": 0 1985 } 1986 )"_json; 1987 parseI2CCompareBit(element); 1988 ADD_FAILURE() << "Should not have reached this line."; 1989 } 1990 catch (const std::invalid_argument& e) 1991 { 1992 EXPECT_STREQ(e.what(), "Element is not a bit position"); 1993 } 1994 1995 // Test where fails: value value is invalid 1996 try 1997 { 1998 const json element = R"( 1999 { 2000 "register": "0xA0", 2001 "position": 3, 2002 "value": 2 2003 } 2004 )"_json; 2005 parseI2CCompareBit(element); 2006 ADD_FAILURE() << "Should not have reached this line."; 2007 } 2008 catch (const std::invalid_argument& e) 2009 { 2010 EXPECT_STREQ(e.what(), "Element is not a bit value"); 2011 } 2012 2013 // Test where fails: Required register property not specified 2014 try 2015 { 2016 const json element = R"( 2017 { 2018 "position": 3, 2019 "value": 0 2020 } 2021 )"_json; 2022 parseI2CCompareBit(element); 2023 ADD_FAILURE() << "Should not have reached this line."; 2024 } 2025 catch (const std::invalid_argument& e) 2026 { 2027 EXPECT_STREQ(e.what(), "Required property missing: register"); 2028 } 2029 2030 // Test where fails: Required position property not specified 2031 try 2032 { 2033 const json element = R"( 2034 { 2035 "register": "0xA0", 2036 "value": 0 2037 } 2038 )"_json; 2039 parseI2CCompareBit(element); 2040 ADD_FAILURE() << "Should not have reached this line."; 2041 } 2042 catch (const std::invalid_argument& e) 2043 { 2044 EXPECT_STREQ(e.what(), "Required property missing: position"); 2045 } 2046 2047 // Test where fails: Required value property not specified 2048 try 2049 { 2050 const json element = R"( 2051 { 2052 "register": "0xA0", 2053 "position": 3 2054 } 2055 )"_json; 2056 parseI2CCompareBit(element); 2057 ADD_FAILURE() << "Should not have reached this line."; 2058 } 2059 catch (const std::invalid_argument& e) 2060 { 2061 EXPECT_STREQ(e.what(), "Required property missing: value"); 2062 } 2063 } 2064 2065 TEST(ConfigFileParserTests, ParseI2CCompareByte) 2066 { 2067 // Test where works: Only required properties specified 2068 { 2069 const json element = R"( 2070 { 2071 "register": "0x0A", 2072 "value": "0xCC" 2073 } 2074 )"_json; 2075 std::unique_ptr<I2CCompareByteAction> action = 2076 parseI2CCompareByte(element); 2077 EXPECT_EQ(action->getRegister(), 0x0A); 2078 EXPECT_EQ(action->getValue(), 0xCC); 2079 EXPECT_EQ(action->getMask(), 0xFF); 2080 } 2081 2082 // Test where works: All properties specified 2083 { 2084 const json element = R"( 2085 { 2086 "register": "0x0A", 2087 "value": "0xCC", 2088 "mask": "0xF7" 2089 } 2090 )"_json; 2091 std::unique_ptr<I2CCompareByteAction> action = 2092 parseI2CCompareByte(element); 2093 EXPECT_EQ(action->getRegister(), 0x0A); 2094 EXPECT_EQ(action->getValue(), 0xCC); 2095 EXPECT_EQ(action->getMask(), 0xF7); 2096 } 2097 2098 // Test where fails: Element is not an object 2099 try 2100 { 2101 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2102 parseI2CCompareByte(element); 2103 ADD_FAILURE() << "Should not have reached this line."; 2104 } 2105 catch (const std::invalid_argument& e) 2106 { 2107 EXPECT_STREQ(e.what(), "Element is not an object"); 2108 } 2109 2110 // Test where fails: Invalid property specified 2111 try 2112 { 2113 const json element = R"( 2114 { 2115 "register": "0x0A", 2116 "value": "0xCC", 2117 "mask": "0xF7", 2118 "foo": 1 2119 } 2120 )"_json; 2121 parseI2CCompareByte(element); 2122 ADD_FAILURE() << "Should not have reached this line."; 2123 } 2124 catch (const std::invalid_argument& e) 2125 { 2126 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2127 } 2128 2129 // Test where fails: register value is invalid 2130 try 2131 { 2132 const json element = R"( 2133 { 2134 "register": "0x0Z", 2135 "value": "0xCC", 2136 "mask": "0xF7" 2137 } 2138 )"_json; 2139 parseI2CCompareByte(element); 2140 ADD_FAILURE() << "Should not have reached this line."; 2141 } 2142 catch (const std::invalid_argument& e) 2143 { 2144 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2145 } 2146 2147 // Test where fails: value value is invalid 2148 try 2149 { 2150 const json element = R"( 2151 { 2152 "register": "0x0A", 2153 "value": "0xCCC", 2154 "mask": "0xF7" 2155 } 2156 )"_json; 2157 parseI2CCompareByte(element); 2158 ADD_FAILURE() << "Should not have reached this line."; 2159 } 2160 catch (const std::invalid_argument& e) 2161 { 2162 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2163 } 2164 2165 // Test where fails: mask value is invalid 2166 try 2167 { 2168 const json element = R"( 2169 { 2170 "register": "0x0A", 2171 "value": "0xCC", 2172 "mask": "F7" 2173 } 2174 )"_json; 2175 parseI2CCompareByte(element); 2176 ADD_FAILURE() << "Should not have reached this line."; 2177 } 2178 catch (const std::invalid_argument& e) 2179 { 2180 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2181 } 2182 2183 // Test where fails: Required register property not specified 2184 try 2185 { 2186 const json element = R"( 2187 { 2188 "value": "0xCC", 2189 "mask": "0xF7" 2190 } 2191 )"_json; 2192 parseI2CCompareByte(element); 2193 ADD_FAILURE() << "Should not have reached this line."; 2194 } 2195 catch (const std::invalid_argument& e) 2196 { 2197 EXPECT_STREQ(e.what(), "Required property missing: register"); 2198 } 2199 2200 // Test where fails: Required value property not specified 2201 try 2202 { 2203 const json element = R"( 2204 { 2205 "register": "0x0A", 2206 "mask": "0xF7" 2207 } 2208 )"_json; 2209 parseI2CCompareByte(element); 2210 ADD_FAILURE() << "Should not have reached this line."; 2211 } 2212 catch (const std::invalid_argument& e) 2213 { 2214 EXPECT_STREQ(e.what(), "Required property missing: value"); 2215 } 2216 } 2217 2218 TEST(ConfigFileParserTests, ParseI2CCompareBytes) 2219 { 2220 // Test where works: Only required properties specified 2221 { 2222 const json element = R"( 2223 { 2224 "register": "0x0A", 2225 "values": [ "0xCC", "0xFF" ] 2226 } 2227 )"_json; 2228 std::unique_ptr<I2CCompareBytesAction> action = 2229 parseI2CCompareBytes(element); 2230 EXPECT_EQ(action->getRegister(), 0x0A); 2231 EXPECT_EQ(action->getValues().size(), 2); 2232 EXPECT_EQ(action->getValues()[0], 0xCC); 2233 EXPECT_EQ(action->getValues()[1], 0xFF); 2234 EXPECT_EQ(action->getMasks().size(), 2); 2235 EXPECT_EQ(action->getMasks()[0], 0xFF); 2236 EXPECT_EQ(action->getMasks()[1], 0xFF); 2237 } 2238 2239 // Test where works: All properties specified 2240 { 2241 const json element = R"( 2242 { 2243 "register": "0x0A", 2244 "values": [ "0xCC", "0xFF" ], 2245 "masks": [ "0x7F", "0x77" ] 2246 } 2247 )"_json; 2248 std::unique_ptr<I2CCompareBytesAction> action = 2249 parseI2CCompareBytes(element); 2250 EXPECT_EQ(action->getRegister(), 0x0A); 2251 EXPECT_EQ(action->getValues().size(), 2); 2252 EXPECT_EQ(action->getValues()[0], 0xCC); 2253 EXPECT_EQ(action->getValues()[1], 0xFF); 2254 EXPECT_EQ(action->getMasks().size(), 2); 2255 EXPECT_EQ(action->getMasks()[0], 0x7F); 2256 EXPECT_EQ(action->getMasks()[1], 0x77); 2257 } 2258 2259 // Test where fails: Element is not an object 2260 try 2261 { 2262 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2263 parseI2CCompareBytes(element); 2264 ADD_FAILURE() << "Should not have reached this line."; 2265 } 2266 catch (const std::invalid_argument& e) 2267 { 2268 EXPECT_STREQ(e.what(), "Element is not an object"); 2269 } 2270 2271 // Test where fails: Invalid property specified 2272 try 2273 { 2274 const json element = R"( 2275 { 2276 "register": "0x0A", 2277 "values": [ "0xCC", "0xFF" ], 2278 "masks": [ "0x7F", "0x7F" ], 2279 "foo": 1 2280 } 2281 )"_json; 2282 parseI2CCompareBytes(element); 2283 ADD_FAILURE() << "Should not have reached this line."; 2284 } 2285 catch (const std::invalid_argument& e) 2286 { 2287 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2288 } 2289 2290 // Test where fails: register value is invalid 2291 try 2292 { 2293 const json element = R"( 2294 { 2295 "register": "0x0Z", 2296 "values": [ "0xCC", "0xFF" ], 2297 "masks": [ "0x7F", "0x7F" ] 2298 } 2299 )"_json; 2300 parseI2CCompareBytes(element); 2301 ADD_FAILURE() << "Should not have reached this line."; 2302 } 2303 catch (const std::invalid_argument& e) 2304 { 2305 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2306 } 2307 2308 // Test where fails: values value is invalid 2309 try 2310 { 2311 const json element = R"( 2312 { 2313 "register": "0x0A", 2314 "values": [ "0xCCC", "0xFF" ], 2315 "masks": [ "0x7F", "0x7F" ] 2316 } 2317 )"_json; 2318 parseI2CCompareBytes(element); 2319 ADD_FAILURE() << "Should not have reached this line."; 2320 } 2321 catch (const std::invalid_argument& e) 2322 { 2323 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2324 } 2325 2326 // Test where fails: masks value is invalid 2327 try 2328 { 2329 const json element = R"( 2330 { 2331 "register": "0x0A", 2332 "values": [ "0xCC", "0xFF" ], 2333 "masks": [ "F", "0x7F" ] 2334 } 2335 )"_json; 2336 parseI2CCompareBytes(element); 2337 ADD_FAILURE() << "Should not have reached this line."; 2338 } 2339 catch (const std::invalid_argument& e) 2340 { 2341 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2342 } 2343 2344 // Test where fails: number of elements in masks is invalid 2345 try 2346 { 2347 const json element = R"( 2348 { 2349 "register": "0x0A", 2350 "values": [ "0xCC", "0xFF" ], 2351 "masks": [ "0x7F" ] 2352 } 2353 )"_json; 2354 parseI2CCompareBytes(element); 2355 ADD_FAILURE() << "Should not have reached this line."; 2356 } 2357 catch (const std::invalid_argument& e) 2358 { 2359 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 2360 } 2361 2362 // Test where fails: Required register property not specified 2363 try 2364 { 2365 const json element = R"( 2366 { 2367 "values": [ "0xCC", "0xFF" ] 2368 } 2369 )"_json; 2370 parseI2CCompareBytes(element); 2371 ADD_FAILURE() << "Should not have reached this line."; 2372 } 2373 catch (const std::invalid_argument& e) 2374 { 2375 EXPECT_STREQ(e.what(), "Required property missing: register"); 2376 } 2377 2378 // Test where fails: Required values property not specified 2379 try 2380 { 2381 const json element = R"( 2382 { 2383 "register": "0x0A" 2384 } 2385 )"_json; 2386 parseI2CCompareBytes(element); 2387 ADD_FAILURE() << "Should not have reached this line."; 2388 } 2389 catch (const std::invalid_argument& e) 2390 { 2391 EXPECT_STREQ(e.what(), "Required property missing: values"); 2392 } 2393 } 2394 2395 TEST(ConfigFileParserTests, ParseI2CWriteBit) 2396 { 2397 // Test where works 2398 { 2399 const json element = R"( 2400 { 2401 "register": "0xA0", 2402 "position": 3, 2403 "value": 0 2404 } 2405 )"_json; 2406 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element); 2407 EXPECT_EQ(action->getRegister(), 0xA0); 2408 EXPECT_EQ(action->getPosition(), 3); 2409 EXPECT_EQ(action->getValue(), 0); 2410 } 2411 2412 // Test where fails: Invalid property specified 2413 try 2414 { 2415 const json element = R"( 2416 { 2417 "register": "0xA0", 2418 "position": 3, 2419 "value": 0, 2420 "foo": 3 2421 } 2422 )"_json; 2423 parseI2CWriteBit(element); 2424 ADD_FAILURE() << "Should not have reached this line."; 2425 } 2426 catch (const std::invalid_argument& e) 2427 { 2428 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2429 } 2430 2431 // Test where fails: Element is not an object 2432 try 2433 { 2434 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2435 parseI2CWriteBit(element); 2436 ADD_FAILURE() << "Should not have reached this line."; 2437 } 2438 catch (const std::invalid_argument& e) 2439 { 2440 EXPECT_STREQ(e.what(), "Element is not an object"); 2441 } 2442 2443 // Test where fails: register value is invalid 2444 try 2445 { 2446 const json element = R"( 2447 { 2448 "register": "0xAG", 2449 "position": 3, 2450 "value": 0 2451 } 2452 )"_json; 2453 parseI2CWriteBit(element); 2454 ADD_FAILURE() << "Should not have reached this line."; 2455 } 2456 catch (const std::invalid_argument& e) 2457 { 2458 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2459 } 2460 2461 // Test where fails: position value is invalid 2462 try 2463 { 2464 const json element = R"( 2465 { 2466 "register": "0xA0", 2467 "position": 8, 2468 "value": 0 2469 } 2470 )"_json; 2471 parseI2CWriteBit(element); 2472 ADD_FAILURE() << "Should not have reached this line."; 2473 } 2474 catch (const std::invalid_argument& e) 2475 { 2476 EXPECT_STREQ(e.what(), "Element is not a bit position"); 2477 } 2478 2479 // Test where fails: value value is invalid 2480 try 2481 { 2482 const json element = R"( 2483 { 2484 "register": "0xA0", 2485 "position": 3, 2486 "value": 2 2487 } 2488 )"_json; 2489 parseI2CWriteBit(element); 2490 ADD_FAILURE() << "Should not have reached this line."; 2491 } 2492 catch (const std::invalid_argument& e) 2493 { 2494 EXPECT_STREQ(e.what(), "Element is not a bit value"); 2495 } 2496 2497 // Test where fails: Required register property not specified 2498 try 2499 { 2500 const json element = R"( 2501 { 2502 "position": 3, 2503 "value": 0 2504 } 2505 )"_json; 2506 parseI2CWriteBit(element); 2507 ADD_FAILURE() << "Should not have reached this line."; 2508 } 2509 catch (const std::invalid_argument& e) 2510 { 2511 EXPECT_STREQ(e.what(), "Required property missing: register"); 2512 } 2513 2514 // Test where fails: Required position property not specified 2515 try 2516 { 2517 const json element = R"( 2518 { 2519 "register": "0xA0", 2520 "value": 0 2521 } 2522 )"_json; 2523 parseI2CWriteBit(element); 2524 ADD_FAILURE() << "Should not have reached this line."; 2525 } 2526 catch (const std::invalid_argument& e) 2527 { 2528 EXPECT_STREQ(e.what(), "Required property missing: position"); 2529 } 2530 2531 // Test where fails: Required value property not specified 2532 try 2533 { 2534 const json element = R"( 2535 { 2536 "register": "0xA0", 2537 "position": 3 2538 } 2539 )"_json; 2540 parseI2CWriteBit(element); 2541 ADD_FAILURE() << "Should not have reached this line."; 2542 } 2543 catch (const std::invalid_argument& e) 2544 { 2545 EXPECT_STREQ(e.what(), "Required property missing: value"); 2546 } 2547 } 2548 2549 TEST(ConfigFileParserTests, ParseI2CWriteByte) 2550 { 2551 // Test where works: Only required properties specified 2552 { 2553 const json element = R"( 2554 { 2555 "register": "0x0A", 2556 "value": "0xCC" 2557 } 2558 )"_json; 2559 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 2560 EXPECT_EQ(action->getRegister(), 0x0A); 2561 EXPECT_EQ(action->getValue(), 0xCC); 2562 EXPECT_EQ(action->getMask(), 0xFF); 2563 } 2564 2565 // Test where works: All properties specified 2566 { 2567 const json element = R"( 2568 { 2569 "register": "0x0A", 2570 "value": "0xCC", 2571 "mask": "0xF7" 2572 } 2573 )"_json; 2574 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 2575 EXPECT_EQ(action->getRegister(), 0x0A); 2576 EXPECT_EQ(action->getValue(), 0xCC); 2577 EXPECT_EQ(action->getMask(), 0xF7); 2578 } 2579 2580 // Test where fails: Element is not an object 2581 try 2582 { 2583 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2584 parseI2CWriteByte(element); 2585 ADD_FAILURE() << "Should not have reached this line."; 2586 } 2587 catch (const std::invalid_argument& e) 2588 { 2589 EXPECT_STREQ(e.what(), "Element is not an object"); 2590 } 2591 2592 // Test where fails: Invalid property specified 2593 try 2594 { 2595 const json element = R"( 2596 { 2597 "register": "0x0A", 2598 "value": "0xCC", 2599 "mask": "0xF7", 2600 "foo": 1 2601 } 2602 )"_json; 2603 parseI2CWriteByte(element); 2604 ADD_FAILURE() << "Should not have reached this line."; 2605 } 2606 catch (const std::invalid_argument& e) 2607 { 2608 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2609 } 2610 2611 // Test where fails: register value is invalid 2612 try 2613 { 2614 const json element = R"( 2615 { 2616 "register": "0x0Z", 2617 "value": "0xCC", 2618 "mask": "0xF7" 2619 } 2620 )"_json; 2621 parseI2CWriteByte(element); 2622 ADD_FAILURE() << "Should not have reached this line."; 2623 } 2624 catch (const std::invalid_argument& e) 2625 { 2626 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2627 } 2628 2629 // Test where fails: value value is invalid 2630 try 2631 { 2632 const json element = R"( 2633 { 2634 "register": "0x0A", 2635 "value": "0xCCC", 2636 "mask": "0xF7" 2637 } 2638 )"_json; 2639 parseI2CWriteByte(element); 2640 ADD_FAILURE() << "Should not have reached this line."; 2641 } 2642 catch (const std::invalid_argument& e) 2643 { 2644 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2645 } 2646 2647 // Test where fails: mask value is invalid 2648 try 2649 { 2650 const json element = R"( 2651 { 2652 "register": "0x0A", 2653 "value": "0xCC", 2654 "mask": "F7" 2655 } 2656 )"_json; 2657 parseI2CWriteByte(element); 2658 ADD_FAILURE() << "Should not have reached this line."; 2659 } 2660 catch (const std::invalid_argument& e) 2661 { 2662 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2663 } 2664 2665 // Test where fails: Required register property not specified 2666 try 2667 { 2668 const json element = R"( 2669 { 2670 "value": "0xCC", 2671 "mask": "0xF7" 2672 } 2673 )"_json; 2674 parseI2CWriteByte(element); 2675 ADD_FAILURE() << "Should not have reached this line."; 2676 } 2677 catch (const std::invalid_argument& e) 2678 { 2679 EXPECT_STREQ(e.what(), "Required property missing: register"); 2680 } 2681 2682 // Test where fails: Required value property not specified 2683 try 2684 { 2685 const json element = R"( 2686 { 2687 "register": "0x0A", 2688 "mask": "0xF7" 2689 } 2690 )"_json; 2691 parseI2CWriteByte(element); 2692 ADD_FAILURE() << "Should not have reached this line."; 2693 } 2694 catch (const std::invalid_argument& e) 2695 { 2696 EXPECT_STREQ(e.what(), "Required property missing: value"); 2697 } 2698 } 2699 2700 TEST(ConfigFileParserTests, ParseI2CWriteBytes) 2701 { 2702 // Test where works: Only required properties specified 2703 { 2704 const json element = R"( 2705 { 2706 "register": "0x0A", 2707 "values": [ "0xCC", "0xFF" ] 2708 } 2709 )"_json; 2710 std::unique_ptr<I2CWriteBytesAction> action = 2711 parseI2CWriteBytes(element); 2712 EXPECT_EQ(action->getRegister(), 0x0A); 2713 EXPECT_EQ(action->getValues().size(), 2); 2714 EXPECT_EQ(action->getValues()[0], 0xCC); 2715 EXPECT_EQ(action->getValues()[1], 0xFF); 2716 EXPECT_EQ(action->getMasks().size(), 0); 2717 } 2718 2719 // Test where works: All properties specified 2720 { 2721 const json element = R"( 2722 { 2723 "register": "0x0A", 2724 "values": [ "0xCC", "0xFF" ], 2725 "masks": [ "0x7F", "0x77" ] 2726 } 2727 )"_json; 2728 std::unique_ptr<I2CWriteBytesAction> action = 2729 parseI2CWriteBytes(element); 2730 EXPECT_EQ(action->getRegister(), 0x0A); 2731 EXPECT_EQ(action->getValues().size(), 2); 2732 EXPECT_EQ(action->getValues()[0], 0xCC); 2733 EXPECT_EQ(action->getValues()[1], 0xFF); 2734 EXPECT_EQ(action->getMasks().size(), 2); 2735 EXPECT_EQ(action->getMasks()[0], 0x7F); 2736 EXPECT_EQ(action->getMasks()[1], 0x77); 2737 } 2738 2739 // Test where fails: Element is not an object 2740 try 2741 { 2742 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2743 parseI2CWriteBytes(element); 2744 ADD_FAILURE() << "Should not have reached this line."; 2745 } 2746 catch (const std::invalid_argument& e) 2747 { 2748 EXPECT_STREQ(e.what(), "Element is not an object"); 2749 } 2750 2751 // Test where fails: Invalid property specified 2752 try 2753 { 2754 const json element = R"( 2755 { 2756 "register": "0x0A", 2757 "values": [ "0xCC", "0xFF" ], 2758 "masks": [ "0x7F", "0x7F" ], 2759 "foo": 1 2760 } 2761 )"_json; 2762 parseI2CWriteBytes(element); 2763 ADD_FAILURE() << "Should not have reached this line."; 2764 } 2765 catch (const std::invalid_argument& e) 2766 { 2767 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2768 } 2769 2770 // Test where fails: register value is invalid 2771 try 2772 { 2773 const json element = R"( 2774 { 2775 "register": "0x0Z", 2776 "values": [ "0xCC", "0xFF" ], 2777 "masks": [ "0x7F", "0x7F" ] 2778 } 2779 )"_json; 2780 parseI2CWriteBytes(element); 2781 ADD_FAILURE() << "Should not have reached this line."; 2782 } 2783 catch (const std::invalid_argument& e) 2784 { 2785 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2786 } 2787 2788 // Test where fails: values value is invalid 2789 try 2790 { 2791 const json element = R"( 2792 { 2793 "register": "0x0A", 2794 "values": [ "0xCCC", "0xFF" ], 2795 "masks": [ "0x7F", "0x7F" ] 2796 } 2797 )"_json; 2798 parseI2CWriteBytes(element); 2799 ADD_FAILURE() << "Should not have reached this line."; 2800 } 2801 catch (const std::invalid_argument& e) 2802 { 2803 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2804 } 2805 2806 // Test where fails: masks value is invalid 2807 try 2808 { 2809 const json element = R"( 2810 { 2811 "register": "0x0A", 2812 "values": [ "0xCC", "0xFF" ], 2813 "masks": [ "F", "0x7F" ] 2814 } 2815 )"_json; 2816 parseI2CWriteBytes(element); 2817 ADD_FAILURE() << "Should not have reached this line."; 2818 } 2819 catch (const std::invalid_argument& e) 2820 { 2821 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2822 } 2823 2824 // Test where fails: number of elements in masks is invalid 2825 try 2826 { 2827 const json element = R"( 2828 { 2829 "register": "0x0A", 2830 "values": [ "0xCC", "0xFF" ], 2831 "masks": [ "0x7F" ] 2832 } 2833 )"_json; 2834 parseI2CWriteBytes(element); 2835 ADD_FAILURE() << "Should not have reached this line."; 2836 } 2837 catch (const std::invalid_argument& e) 2838 { 2839 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 2840 } 2841 2842 // Test where fails: Required register property not specified 2843 try 2844 { 2845 const json element = R"( 2846 { 2847 "values": [ "0xCC", "0xFF" ] 2848 } 2849 )"_json; 2850 parseI2CWriteBytes(element); 2851 ADD_FAILURE() << "Should not have reached this line."; 2852 } 2853 catch (const std::invalid_argument& e) 2854 { 2855 EXPECT_STREQ(e.what(), "Required property missing: register"); 2856 } 2857 2858 // Test where fails: Required values property not specified 2859 try 2860 { 2861 const json element = R"( 2862 { 2863 "register": "0x0A" 2864 } 2865 )"_json; 2866 parseI2CWriteBytes(element); 2867 ADD_FAILURE() << "Should not have reached this line."; 2868 } 2869 catch (const std::invalid_argument& e) 2870 { 2871 EXPECT_STREQ(e.what(), "Required property missing: values"); 2872 } 2873 } 2874 2875 TEST(ConfigFileParserTests, ParseIf) 2876 { 2877 // Test where works: Only required properties specified 2878 { 2879 const json element = R"( 2880 { 2881 "condition": { "run_rule": "is_downlevel_regulator" }, 2882 "then": [ { "run_rule": "configure_downlevel_regulator" }, 2883 { "run_rule": "configure_standard_regulator" } ] 2884 } 2885 )"_json; 2886 std::unique_ptr<IfAction> action = parseIf(element); 2887 EXPECT_NE(action->getConditionAction().get(), nullptr); 2888 EXPECT_EQ(action->getThenActions().size(), 2); 2889 EXPECT_EQ(action->getElseActions().size(), 0); 2890 } 2891 2892 // Test where works: All properties specified 2893 { 2894 const json element = R"( 2895 { 2896 "condition": { "run_rule": "is_downlevel_regulator" }, 2897 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2898 "else": [ { "run_rule": "configure_standard_regulator" } ] 2899 } 2900 )"_json; 2901 std::unique_ptr<IfAction> action = parseIf(element); 2902 EXPECT_NE(action->getConditionAction().get(), nullptr); 2903 EXPECT_EQ(action->getThenActions().size(), 1); 2904 EXPECT_EQ(action->getElseActions().size(), 1); 2905 } 2906 2907 // Test where fails: Required condition property not specified 2908 try 2909 { 2910 const json element = R"( 2911 { 2912 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2913 "else": [ { "run_rule": "configure_standard_regulator" } ] 2914 } 2915 )"_json; 2916 parseIf(element); 2917 ADD_FAILURE() << "Should not have reached this line."; 2918 } 2919 catch (const std::invalid_argument& e) 2920 { 2921 EXPECT_STREQ(e.what(), "Required property missing: condition"); 2922 } 2923 2924 // Test where fails: Required then property not specified 2925 try 2926 { 2927 const json element = R"( 2928 { 2929 "condition": { "run_rule": "is_downlevel_regulator" }, 2930 "else": [ { "run_rule": "configure_standard_regulator" } ] 2931 } 2932 )"_json; 2933 parseIf(element); 2934 ADD_FAILURE() << "Should not have reached this line."; 2935 } 2936 catch (const std::invalid_argument& e) 2937 { 2938 EXPECT_STREQ(e.what(), "Required property missing: then"); 2939 } 2940 2941 // Test where fails: condition value is invalid 2942 try 2943 { 2944 const json element = R"( 2945 { 2946 "condition": 1, 2947 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2948 "else": [ { "run_rule": "configure_standard_regulator" } ] 2949 } 2950 )"_json; 2951 parseIf(element); 2952 ADD_FAILURE() << "Should not have reached this line."; 2953 } 2954 catch (const std::invalid_argument& e) 2955 { 2956 EXPECT_STREQ(e.what(), "Element is not an object"); 2957 } 2958 2959 // Test where fails: then value is invalid 2960 try 2961 { 2962 const json element = R"( 2963 { 2964 "condition": { "run_rule": "is_downlevel_regulator" }, 2965 "then": "foo", 2966 "else": [ { "run_rule": "configure_standard_regulator" } ] 2967 } 2968 )"_json; 2969 parseIf(element); 2970 ADD_FAILURE() << "Should not have reached this line."; 2971 } 2972 catch (const std::invalid_argument& e) 2973 { 2974 EXPECT_STREQ(e.what(), "Element is not an array"); 2975 } 2976 2977 // Test where fails: else value is invalid 2978 try 2979 { 2980 const json element = R"( 2981 { 2982 "condition": { "run_rule": "is_downlevel_regulator" }, 2983 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2984 "else": 1 2985 } 2986 )"_json; 2987 parseIf(element); 2988 ADD_FAILURE() << "Should not have reached this line."; 2989 } 2990 catch (const std::invalid_argument& e) 2991 { 2992 EXPECT_STREQ(e.what(), "Element is not an array"); 2993 } 2994 2995 // Test where fails: Invalid property specified 2996 try 2997 { 2998 const json element = R"( 2999 { 3000 "condition": { "run_rule": "is_downlevel_regulator" }, 3001 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 3002 "foo": "bar" 3003 } 3004 )"_json; 3005 parseIf(element); 3006 ADD_FAILURE() << "Should not have reached this line."; 3007 } 3008 catch (const std::invalid_argument& e) 3009 { 3010 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3011 } 3012 3013 // Test where fails: Element is not an object 3014 try 3015 { 3016 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3017 parseIf(element); 3018 ADD_FAILURE() << "Should not have reached this line."; 3019 } 3020 catch (const std::invalid_argument& e) 3021 { 3022 EXPECT_STREQ(e.what(), "Element is not an object"); 3023 } 3024 } 3025 3026 TEST(ConfigFileParserTests, ParseInventoryPath) 3027 { 3028 // Test where works: Inventory path has a leading '/' 3029 { 3030 const json element = "/system/chassis/motherboard/cpu3"; 3031 std::string value = parseInventoryPath(element); 3032 EXPECT_EQ( 3033 value, 3034 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3"); 3035 } 3036 3037 // Test where works: Inventory path does not have a leading '/' 3038 { 3039 const json element = "system/chassis/motherboard/cpu1"; 3040 std::string value = parseInventoryPath(element); 3041 EXPECT_EQ( 3042 value, 3043 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1"); 3044 } 3045 3046 // Test where fails: JSON element is not a string 3047 try 3048 { 3049 const json element = R"( { "foo": "bar" } )"_json; 3050 parseInventoryPath(element); 3051 ADD_FAILURE() << "Should not have reached this line."; 3052 } 3053 catch (const std::invalid_argument& e) 3054 { 3055 EXPECT_STREQ(e.what(), "Element is not a string"); 3056 } 3057 3058 // Test where fails: JSON element contains an empty string 3059 try 3060 { 3061 const json element = ""; 3062 parseInventoryPath(element); 3063 ADD_FAILURE() << "Should not have reached this line."; 3064 } 3065 catch (const std::invalid_argument& e) 3066 { 3067 EXPECT_STREQ(e.what(), "Element contains an empty string"); 3068 } 3069 } 3070 3071 TEST(ConfigFileParserTests, ParseLogPhaseFault) 3072 { 3073 // Test where works 3074 { 3075 const json element = R"( 3076 { 3077 "type": "n+1" 3078 } 3079 )"_json; 3080 std::unique_ptr<LogPhaseFaultAction> action = 3081 parseLogPhaseFault(element); 3082 EXPECT_EQ(action->getType(), PhaseFaultType::n_plus_1); 3083 } 3084 3085 // Test where fails: Element is not an object 3086 try 3087 { 3088 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3089 parseLogPhaseFault(element); 3090 ADD_FAILURE() << "Should not have reached this line."; 3091 } 3092 catch (const std::invalid_argument& e) 3093 { 3094 EXPECT_STREQ(e.what(), "Element is not an object"); 3095 } 3096 3097 // Test where fails: Required type property not specified 3098 try 3099 { 3100 const json element = R"( 3101 { 3102 } 3103 )"_json; 3104 parseLogPhaseFault(element); 3105 ADD_FAILURE() << "Should not have reached this line."; 3106 } 3107 catch (const std::invalid_argument& e) 3108 { 3109 EXPECT_STREQ(e.what(), "Required property missing: type"); 3110 } 3111 3112 // Test where fails: type value is invalid 3113 try 3114 { 3115 const json element = R"( 3116 { 3117 "type": "n+2" 3118 } 3119 )"_json; 3120 parseLogPhaseFault(element); 3121 ADD_FAILURE() << "Should not have reached this line."; 3122 } 3123 catch (const std::invalid_argument& e) 3124 { 3125 EXPECT_STREQ(e.what(), "Element is not a phase fault type"); 3126 } 3127 3128 // Test where fails: Invalid property specified 3129 try 3130 { 3131 const json element = R"( 3132 { 3133 "type": "n+1", 3134 "foo": 1 3135 } 3136 )"_json; 3137 parseLogPhaseFault(element); 3138 ADD_FAILURE() << "Should not have reached this line."; 3139 } 3140 catch (const std::invalid_argument& e) 3141 { 3142 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3143 } 3144 } 3145 3146 TEST(ConfigFileParserTests, ParseNot) 3147 { 3148 // Test where works 3149 { 3150 const json element = R"( 3151 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 3152 )"_json; 3153 std::unique_ptr<NotAction> action = parseNot(element); 3154 EXPECT_NE(action->getAction().get(), nullptr); 3155 } 3156 3157 // Test where fails: Element is not an object 3158 try 3159 { 3160 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3161 parseNot(element); 3162 ADD_FAILURE() << "Should not have reached this line."; 3163 } 3164 catch (const std::invalid_argument& e) 3165 { 3166 EXPECT_STREQ(e.what(), "Element is not an object"); 3167 } 3168 } 3169 3170 TEST(ConfigFileParserTests, ParseOr) 3171 { 3172 // Test where works: Element is an array with 2 actions 3173 { 3174 const json element = R"( 3175 [ 3176 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 3177 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 3178 ] 3179 )"_json; 3180 std::unique_ptr<OrAction> action = parseOr(element); 3181 EXPECT_EQ(action->getActions().size(), 2); 3182 } 3183 3184 // Test where fails: Element is an array with 1 action 3185 try 3186 { 3187 const json element = R"( 3188 [ 3189 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 3190 ] 3191 )"_json; 3192 parseOr(element); 3193 ADD_FAILURE() << "Should not have reached this line."; 3194 } 3195 catch (const std::invalid_argument& e) 3196 { 3197 EXPECT_STREQ(e.what(), "Array must contain two or more actions"); 3198 } 3199 3200 // Test where fails: Element is not an array 3201 try 3202 { 3203 const json element = R"( 3204 { 3205 "foo": "bar" 3206 } 3207 )"_json; 3208 parseOr(element); 3209 ADD_FAILURE() << "Should not have reached this line."; 3210 } 3211 catch (const std::invalid_argument& e) 3212 { 3213 EXPECT_STREQ(e.what(), "Element is not an array"); 3214 } 3215 } 3216 3217 TEST(ConfigFileParserTests, ParsePhaseFaultDetection) 3218 { 3219 // Test where works: actions specified: optional properties not specified 3220 { 3221 const json element = R"( 3222 { 3223 "actions": [ 3224 { "run_rule": "detect_phase_fault_rule" } 3225 ] 3226 } 3227 )"_json; 3228 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = 3229 parsePhaseFaultDetection(element); 3230 EXPECT_EQ(phaseFaultDetection->getActions().size(), 1); 3231 EXPECT_EQ(phaseFaultDetection->getDeviceID(), ""); 3232 } 3233 3234 // Test where works: rule_id specified: optional properties specified 3235 { 3236 const json element = R"( 3237 { 3238 "comments": [ "Detect phase fault using I/O expander" ], 3239 "device_id": "io_expander", 3240 "rule_id": "detect_phase_fault_rule" 3241 } 3242 )"_json; 3243 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = 3244 parsePhaseFaultDetection(element); 3245 EXPECT_EQ(phaseFaultDetection->getActions().size(), 1); 3246 EXPECT_EQ(phaseFaultDetection->getDeviceID(), "io_expander"); 3247 } 3248 3249 // Test where fails: Element is not an object 3250 try 3251 { 3252 const json element = R"( [ "foo", "bar" ] )"_json; 3253 parsePhaseFaultDetection(element); 3254 ADD_FAILURE() << "Should not have reached this line."; 3255 } 3256 catch (const std::invalid_argument& e) 3257 { 3258 EXPECT_STREQ(e.what(), "Element is not an object"); 3259 } 3260 3261 // Test where fails: device_id value is invalid 3262 try 3263 { 3264 const json element = R"( 3265 { 3266 "device_id": 1, 3267 "rule_id": "detect_phase_fault_rule" 3268 } 3269 )"_json; 3270 parsePhaseFaultDetection(element); 3271 ADD_FAILURE() << "Should not have reached this line."; 3272 } 3273 catch (const std::invalid_argument& e) 3274 { 3275 EXPECT_STREQ(e.what(), "Element is not a string"); 3276 } 3277 3278 // Test where fails: rule_id value is invalid 3279 try 3280 { 3281 const json element = R"( 3282 { 3283 "rule_id": 1 3284 } 3285 )"_json; 3286 parsePhaseFaultDetection(element); 3287 ADD_FAILURE() << "Should not have reached this line."; 3288 } 3289 catch (const std::invalid_argument& e) 3290 { 3291 EXPECT_STREQ(e.what(), "Element is not a string"); 3292 } 3293 3294 // Test where fails: actions object is invalid 3295 try 3296 { 3297 const json element = R"( 3298 { 3299 "actions": 1 3300 } 3301 )"_json; 3302 parsePhaseFaultDetection(element); 3303 ADD_FAILURE() << "Should not have reached this line."; 3304 } 3305 catch (const std::invalid_argument& e) 3306 { 3307 EXPECT_STREQ(e.what(), "Element is not an array"); 3308 } 3309 3310 // Test where fails: Required actions or rule_id property not specified 3311 try 3312 { 3313 const json element = R"( 3314 { 3315 "device_id": "io_expander" 3316 } 3317 )"_json; 3318 parsePhaseFaultDetection(element); 3319 ADD_FAILURE() << "Should not have reached this line."; 3320 } 3321 catch (const std::invalid_argument& e) 3322 { 3323 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3324 "either rule_id or actions"); 3325 } 3326 3327 // Test where fails: Required actions or rule_id property both specified 3328 try 3329 { 3330 const json element = R"( 3331 { 3332 "rule_id": "detect_phase_fault_rule", 3333 "actions": [ 3334 { "run_rule": "detect_phase_fault_rule" } 3335 ] 3336 } 3337 )"_json; 3338 parsePhaseFaultDetection(element); 3339 ADD_FAILURE() << "Should not have reached this line."; 3340 } 3341 catch (const std::invalid_argument& e) 3342 { 3343 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3344 "either rule_id or actions"); 3345 } 3346 3347 // Test where fails: Invalid property specified 3348 try 3349 { 3350 const json element = R"( 3351 { 3352 "foo": "bar", 3353 "actions": [ 3354 { "run_rule": "detect_phase_fault_rule" } 3355 ] 3356 } 3357 )"_json; 3358 parsePhaseFaultDetection(element); 3359 ADD_FAILURE() << "Should not have reached this line."; 3360 } 3361 catch (const std::invalid_argument& e) 3362 { 3363 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3364 } 3365 } 3366 3367 TEST(ConfigFileParserTests, ParsePhaseFaultType) 3368 { 3369 // Test where works: n 3370 { 3371 const json element = "n"; 3372 PhaseFaultType type = parsePhaseFaultType(element); 3373 EXPECT_EQ(type, PhaseFaultType::n); 3374 } 3375 3376 // Test where works: n+1 3377 { 3378 const json element = "n+1"; 3379 PhaseFaultType type = parsePhaseFaultType(element); 3380 EXPECT_EQ(type, PhaseFaultType::n_plus_1); 3381 } 3382 3383 // Test where fails: Element is not a phase fault type 3384 try 3385 { 3386 const json element = "n+2"; 3387 parsePhaseFaultType(element); 3388 ADD_FAILURE() << "Should not have reached this line."; 3389 } 3390 catch (const std::invalid_argument& e) 3391 { 3392 EXPECT_STREQ(e.what(), "Element is not a phase fault type"); 3393 } 3394 3395 // Test where fails: Element is not a string 3396 try 3397 { 3398 const json element = R"( { "foo": "bar" } )"_json; 3399 parsePhaseFaultType(element); 3400 ADD_FAILURE() << "Should not have reached this line."; 3401 } 3402 catch (const std::invalid_argument& e) 3403 { 3404 EXPECT_STREQ(e.what(), "Element is not a string"); 3405 } 3406 } 3407 3408 TEST(ConfigFileParserTests, ParsePMBusReadSensor) 3409 { 3410 // Test where works: Only required properties specified 3411 { 3412 const json element = R"( 3413 { 3414 "type": "iout", 3415 "command": "0x8C", 3416 "format": "linear_11" 3417 } 3418 )"_json; 3419 std::unique_ptr<PMBusReadSensorAction> action = 3420 parsePMBusReadSensor(element); 3421 EXPECT_EQ(action->getType(), SensorType::iout); 3422 EXPECT_EQ(action->getCommand(), 0x8C); 3423 EXPECT_EQ(action->getFormat(), 3424 pmbus_utils::SensorDataFormat::linear_11); 3425 EXPECT_EQ(action->getExponent().has_value(), false); 3426 } 3427 3428 // Test where works: All properties specified 3429 { 3430 const json element = R"( 3431 { 3432 "type": "temperature", 3433 "command": "0x7A", 3434 "format": "linear_16", 3435 "exponent": -8 3436 } 3437 )"_json; 3438 std::unique_ptr<PMBusReadSensorAction> action = 3439 parsePMBusReadSensor(element); 3440 EXPECT_EQ(action->getType(), SensorType::temperature); 3441 EXPECT_EQ(action->getCommand(), 0x7A); 3442 EXPECT_EQ(action->getFormat(), 3443 pmbus_utils::SensorDataFormat::linear_16); 3444 EXPECT_EQ(action->getExponent().has_value(), true); 3445 EXPECT_EQ(action->getExponent().value(), -8); 3446 } 3447 3448 // Test where fails: Element is not an object 3449 try 3450 { 3451 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3452 parsePMBusReadSensor(element); 3453 ADD_FAILURE() << "Should not have reached this line."; 3454 } 3455 catch (const std::invalid_argument& e) 3456 { 3457 EXPECT_STREQ(e.what(), "Element is not an object"); 3458 } 3459 3460 // Test where fails: Invalid property specified 3461 try 3462 { 3463 const json element = R"( 3464 { 3465 "type": "iout", 3466 "command": "0x8C", 3467 "format": "linear_11", 3468 "foo": 1 3469 } 3470 )"_json; 3471 parsePMBusReadSensor(element); 3472 ADD_FAILURE() << "Should not have reached this line."; 3473 } 3474 catch (const std::invalid_argument& e) 3475 { 3476 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3477 } 3478 3479 // Test where fails: Required type property not specified 3480 try 3481 { 3482 const json element = R"( 3483 { 3484 "command": "0x8C", 3485 "format": "linear_11" 3486 } 3487 )"_json; 3488 parsePMBusReadSensor(element); 3489 ADD_FAILURE() << "Should not have reached this line."; 3490 } 3491 catch (const std::invalid_argument& e) 3492 { 3493 EXPECT_STREQ(e.what(), "Required property missing: type"); 3494 } 3495 3496 // Test where fails: Required command property not specified 3497 try 3498 { 3499 const json element = R"( 3500 { 3501 "type": "iout", 3502 "format": "linear_11" 3503 } 3504 )"_json; 3505 parsePMBusReadSensor(element); 3506 ADD_FAILURE() << "Should not have reached this line."; 3507 } 3508 catch (const std::invalid_argument& e) 3509 { 3510 EXPECT_STREQ(e.what(), "Required property missing: command"); 3511 } 3512 3513 // Test where fails: Required format property not specified 3514 try 3515 { 3516 const json element = R"( 3517 { 3518 "type": "iout", 3519 "command": "0x8C" 3520 } 3521 )"_json; 3522 parsePMBusReadSensor(element); 3523 ADD_FAILURE() << "Should not have reached this line."; 3524 } 3525 catch (const std::invalid_argument& e) 3526 { 3527 EXPECT_STREQ(e.what(), "Required property missing: format"); 3528 } 3529 3530 // Test where fails: type value is invalid 3531 try 3532 { 3533 const json element = R"( 3534 { 3535 "type": 1, 3536 "command": "0x7A", 3537 "format": "linear_16" 3538 } 3539 )"_json; 3540 parsePMBusReadSensor(element); 3541 ADD_FAILURE() << "Should not have reached this line."; 3542 } 3543 catch (const std::invalid_argument& e) 3544 { 3545 EXPECT_STREQ(e.what(), "Element is not a string"); 3546 } 3547 3548 // Test where fails: command value is invalid 3549 try 3550 { 3551 const json element = R"( 3552 { 3553 "type": "temperature", 3554 "command": 0, 3555 "format": "linear_16" 3556 } 3557 )"_json; 3558 parsePMBusReadSensor(element); 3559 ADD_FAILURE() << "Should not have reached this line."; 3560 } 3561 catch (const std::invalid_argument& e) 3562 { 3563 EXPECT_STREQ(e.what(), "Element is not a string"); 3564 } 3565 3566 // Test where fails: format value is invalid 3567 try 3568 { 3569 const json element = R"( 3570 { 3571 "type": "temperature", 3572 "command": "0x7A", 3573 "format": 1 3574 } 3575 )"_json; 3576 parsePMBusReadSensor(element); 3577 ADD_FAILURE() << "Should not have reached this line."; 3578 } 3579 catch (const std::invalid_argument& e) 3580 { 3581 EXPECT_STREQ(e.what(), "Element is not a string"); 3582 } 3583 3584 // Test where fails: exponent value is invalid 3585 try 3586 { 3587 const json element = R"( 3588 { 3589 "type": "temperature", 3590 "command": "0x7A", 3591 "format": "linear_16", 3592 "exponent": 1.3 3593 } 3594 )"_json; 3595 parsePMBusReadSensor(element); 3596 ADD_FAILURE() << "Should not have reached this line."; 3597 } 3598 catch (const std::invalid_argument& e) 3599 { 3600 EXPECT_STREQ(e.what(), "Element is not an integer"); 3601 } 3602 } 3603 3604 TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand) 3605 { 3606 // Test where works: Only required properties specified 3607 { 3608 const json element = R"( 3609 { 3610 "format": "linear" 3611 } 3612 )"_json; 3613 std::unique_ptr<PMBusWriteVoutCommandAction> action = 3614 parsePMBusWriteVoutCommand(element); 3615 EXPECT_EQ(action->getVolts().has_value(), false); 3616 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 3617 EXPECT_EQ(action->getExponent().has_value(), false); 3618 EXPECT_EQ(action->isVerified(), false); 3619 } 3620 3621 // Test where works: All properties specified 3622 { 3623 const json element = R"( 3624 { 3625 "volts": 1.03, 3626 "format": "linear", 3627 "exponent": -8, 3628 "is_verified": true 3629 } 3630 )"_json; 3631 std::unique_ptr<PMBusWriteVoutCommandAction> action = 3632 parsePMBusWriteVoutCommand(element); 3633 EXPECT_EQ(action->getVolts().has_value(), true); 3634 EXPECT_EQ(action->getVolts().value(), 1.03); 3635 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 3636 EXPECT_EQ(action->getExponent().has_value(), true); 3637 EXPECT_EQ(action->getExponent().value(), -8); 3638 EXPECT_EQ(action->isVerified(), true); 3639 } 3640 3641 // Test where fails: Element is not an object 3642 try 3643 { 3644 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3645 parsePMBusWriteVoutCommand(element); 3646 ADD_FAILURE() << "Should not have reached this line."; 3647 } 3648 catch (const std::invalid_argument& e) 3649 { 3650 EXPECT_STREQ(e.what(), "Element is not an object"); 3651 } 3652 3653 // Test where fails: volts value is invalid 3654 try 3655 { 3656 const json element = R"( 3657 { 3658 "volts": "foo", 3659 "format": "linear" 3660 } 3661 )"_json; 3662 parsePMBusWriteVoutCommand(element); 3663 ADD_FAILURE() << "Should not have reached this line."; 3664 } 3665 catch (const std::invalid_argument& e) 3666 { 3667 EXPECT_STREQ(e.what(), "Element is not a double"); 3668 } 3669 3670 // Test where fails: Required format property not specified 3671 try 3672 { 3673 const json element = R"( 3674 { 3675 "volts": 1.03, 3676 "is_verified": true 3677 } 3678 )"_json; 3679 parsePMBusWriteVoutCommand(element); 3680 ADD_FAILURE() << "Should not have reached this line."; 3681 } 3682 catch (const std::invalid_argument& e) 3683 { 3684 EXPECT_STREQ(e.what(), "Required property missing: format"); 3685 } 3686 3687 // Test where fails: format value is invalid 3688 try 3689 { 3690 const json element = R"( 3691 { 3692 "format": "linear_11" 3693 } 3694 )"_json; 3695 parsePMBusWriteVoutCommand(element); 3696 ADD_FAILURE() << "Should not have reached this line."; 3697 } 3698 catch (const std::invalid_argument& e) 3699 { 3700 EXPECT_STREQ(e.what(), "Invalid format value: linear_11"); 3701 } 3702 3703 // Test where fails: exponent value is invalid 3704 try 3705 { 3706 const json element = R"( 3707 { 3708 "format": "linear", 3709 "exponent": 1.3 3710 } 3711 )"_json; 3712 parsePMBusWriteVoutCommand(element); 3713 ADD_FAILURE() << "Should not have reached this line."; 3714 } 3715 catch (const std::invalid_argument& e) 3716 { 3717 EXPECT_STREQ(e.what(), "Element is not an integer"); 3718 } 3719 3720 // Test where fails: is_verified value is invalid 3721 try 3722 { 3723 const json element = R"( 3724 { 3725 "format": "linear", 3726 "is_verified": "true" 3727 } 3728 )"_json; 3729 parsePMBusWriteVoutCommand(element); 3730 ADD_FAILURE() << "Should not have reached this line."; 3731 } 3732 catch (const std::invalid_argument& e) 3733 { 3734 EXPECT_STREQ(e.what(), "Element is not a boolean"); 3735 } 3736 3737 // Test where fails: Invalid property specified 3738 try 3739 { 3740 const json element = R"( 3741 { 3742 "format": "linear", 3743 "foo": "bar" 3744 } 3745 )"_json; 3746 parsePMBusWriteVoutCommand(element); 3747 ADD_FAILURE() << "Should not have reached this line."; 3748 } 3749 catch (const std::invalid_argument& e) 3750 { 3751 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3752 } 3753 } 3754 3755 TEST(ConfigFileParserTests, ParsePresenceDetection) 3756 { 3757 // Test where works: actions property specified 3758 { 3759 const json element = R"( 3760 { 3761 "actions": [ 3762 { "run_rule": "read_sensors_rule" } 3763 ] 3764 } 3765 )"_json; 3766 std::unique_ptr<PresenceDetection> presenceDetection = 3767 parsePresenceDetection(element); 3768 EXPECT_EQ(presenceDetection->getActions().size(), 1); 3769 } 3770 3771 // Test where works: rule_id property specified 3772 { 3773 const json element = R"( 3774 { 3775 "comments": [ "comments property" ], 3776 "rule_id": "set_voltage_rule" 3777 } 3778 )"_json; 3779 std::unique_ptr<PresenceDetection> presenceDetection = 3780 parsePresenceDetection(element); 3781 EXPECT_EQ(presenceDetection->getActions().size(), 1); 3782 } 3783 3784 // Test where fails: actions object is invalid 3785 try 3786 { 3787 const json element = R"( 3788 { 3789 "actions": 1 3790 } 3791 )"_json; 3792 parsePresenceDetection(element); 3793 ADD_FAILURE() << "Should not have reached this line."; 3794 } 3795 catch (const std::invalid_argument& e) 3796 { 3797 EXPECT_STREQ(e.what(), "Element is not an array"); 3798 } 3799 3800 // Test where fails: rule_id value is invalid 3801 try 3802 { 3803 const json element = R"( 3804 { 3805 "rule_id": 1 3806 } 3807 )"_json; 3808 parsePresenceDetection(element); 3809 ADD_FAILURE() << "Should not have reached this line."; 3810 } 3811 catch (const std::invalid_argument& e) 3812 { 3813 EXPECT_STREQ(e.what(), "Element is not a string"); 3814 } 3815 3816 // Test where fails: Required actions or rule_id property not specified 3817 try 3818 { 3819 const json element = R"( 3820 { 3821 "comments": [ "comments property" ] 3822 } 3823 )"_json; 3824 parsePresenceDetection(element); 3825 ADD_FAILURE() << "Should not have reached this line."; 3826 } 3827 catch (const std::invalid_argument& e) 3828 { 3829 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3830 "either rule_id or actions"); 3831 } 3832 3833 // Test where fails: Required actions or rule_id property both specified 3834 try 3835 { 3836 const json element = R"( 3837 { 3838 "rule_id": "set_voltage_rule", 3839 "actions": [ 3840 { "run_rule": "read_sensors_rule" } 3841 ] 3842 } 3843 )"_json; 3844 parsePresenceDetection(element); 3845 ADD_FAILURE() << "Should not have reached this line."; 3846 } 3847 catch (const std::invalid_argument& e) 3848 { 3849 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3850 "either rule_id or actions"); 3851 } 3852 3853 // Test where fails: Element is not an object 3854 try 3855 { 3856 const json element = R"( [ "foo", "bar" ] )"_json; 3857 parsePresenceDetection(element); 3858 ADD_FAILURE() << "Should not have reached this line."; 3859 } 3860 catch (const std::invalid_argument& e) 3861 { 3862 EXPECT_STREQ(e.what(), "Element is not an object"); 3863 } 3864 3865 // Test where fails: Invalid property specified 3866 try 3867 { 3868 const json element = R"( 3869 { 3870 "foo": "bar", 3871 "actions": [ 3872 { "run_rule": "read_sensors_rule" } 3873 ] 3874 } 3875 )"_json; 3876 parsePresenceDetection(element); 3877 ADD_FAILURE() << "Should not have reached this line."; 3878 } 3879 catch (const std::invalid_argument& e) 3880 { 3881 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3882 } 3883 } 3884 3885 TEST(ConfigFileParserTests, ParseRail) 3886 { 3887 // Test where works: Only required properties specified 3888 { 3889 const json element = R"( 3890 { 3891 "id": "vdd" 3892 } 3893 )"_json; 3894 std::unique_ptr<Rail> rail = parseRail(element); 3895 EXPECT_EQ(rail->getID(), "vdd"); 3896 EXPECT_EQ(rail->getConfiguration(), nullptr); 3897 EXPECT_EQ(rail->getSensorMonitoring(), nullptr); 3898 } 3899 3900 // Test where works: All properties specified 3901 { 3902 const json element = R"( 3903 { 3904 "comments": [ "comments property" ], 3905 "id": "vdd", 3906 "configuration": { 3907 "volts": 1.1, 3908 "actions": [ 3909 { 3910 "pmbus_write_vout_command": { 3911 "format": "linear" 3912 } 3913 } 3914 ] 3915 }, 3916 "sensor_monitoring": { 3917 "actions": [ 3918 { "run_rule": "read_sensors_rule" } 3919 ] 3920 } 3921 } 3922 )"_json; 3923 std::unique_ptr<Rail> rail = parseRail(element); 3924 EXPECT_EQ(rail->getID(), "vdd"); 3925 EXPECT_NE(rail->getConfiguration(), nullptr); 3926 EXPECT_NE(rail->getSensorMonitoring(), nullptr); 3927 } 3928 3929 // Test where fails: id property not specified 3930 try 3931 { 3932 const json element = R"( 3933 { 3934 "configuration": { 3935 "volts": 1.1, 3936 "actions": [ 3937 { 3938 "pmbus_write_vout_command": { 3939 "format": "linear" 3940 } 3941 } 3942 ] 3943 } 3944 } 3945 )"_json; 3946 parseRail(element); 3947 ADD_FAILURE() << "Should not have reached this line."; 3948 } 3949 catch (const std::invalid_argument& e) 3950 { 3951 EXPECT_STREQ(e.what(), "Required property missing: id"); 3952 } 3953 3954 // Test where fails: id property is invalid 3955 try 3956 { 3957 const json element = R"( 3958 { 3959 "id": "", 3960 "configuration": { 3961 "volts": 1.1, 3962 "actions": [ 3963 { 3964 "pmbus_write_vout_command": { 3965 "format": "linear" 3966 } 3967 } 3968 ] 3969 } 3970 } 3971 )"_json; 3972 parseRail(element); 3973 ADD_FAILURE() << "Should not have reached this line."; 3974 } 3975 catch (const std::invalid_argument& e) 3976 { 3977 EXPECT_STREQ(e.what(), "Element contains an empty string"); 3978 } 3979 3980 // Test where fails: Element is not an object 3981 try 3982 { 3983 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3984 parseRail(element); 3985 ADD_FAILURE() << "Should not have reached this line."; 3986 } 3987 catch (const std::invalid_argument& e) 3988 { 3989 EXPECT_STREQ(e.what(), "Element is not an object"); 3990 } 3991 3992 // Test where fails: configuration value is invalid 3993 try 3994 { 3995 const json element = R"( 3996 { 3997 "id": "vdd", 3998 "configuration": "config" 3999 } 4000 )"_json; 4001 parseRail(element); 4002 ADD_FAILURE() << "Should not have reached this line."; 4003 } 4004 catch (const std::invalid_argument& e) 4005 { 4006 EXPECT_STREQ(e.what(), "Element is not an object"); 4007 } 4008 4009 // Test where fails: sensor_monitoring value is invalid 4010 try 4011 { 4012 const json element = R"( 4013 { 4014 "comments": [ "comments property" ], 4015 "id": "vdd", 4016 "configuration": { 4017 "volts": 1.1, 4018 "actions": [ 4019 { 4020 "pmbus_write_vout_command": { 4021 "format": "linear" 4022 } 4023 } 4024 ] 4025 }, 4026 "sensor_monitoring": 1 4027 } 4028 )"_json; 4029 parseRail(element); 4030 ADD_FAILURE() << "Should not have reached this line."; 4031 } 4032 catch (const std::invalid_argument& e) 4033 { 4034 EXPECT_STREQ(e.what(), "Element is not an object"); 4035 } 4036 4037 // Test where fails: Invalid property specified 4038 try 4039 { 4040 const json element = R"( 4041 { 4042 "id": "vdd", 4043 "foo" : true 4044 } 4045 )"_json; 4046 parseRail(element); 4047 ADD_FAILURE() << "Should not have reached this line."; 4048 } 4049 catch (const std::invalid_argument& e) 4050 { 4051 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4052 } 4053 } 4054 4055 TEST(ConfigFileParserTests, ParseRailArray) 4056 { 4057 // Test where works 4058 { 4059 const json element = R"( 4060 [ 4061 { "id": "vdd" }, 4062 { "id": "vio" } 4063 ] 4064 )"_json; 4065 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element); 4066 EXPECT_EQ(rails.size(), 2); 4067 EXPECT_EQ(rails[0]->getID(), "vdd"); 4068 EXPECT_EQ(rails[1]->getID(), "vio"); 4069 } 4070 4071 // Test where fails: Element is not an array 4072 try 4073 { 4074 const json element = R"( 4075 { 4076 "foo": "bar" 4077 } 4078 )"_json; 4079 parseRailArray(element); 4080 ADD_FAILURE() << "Should not have reached this line."; 4081 } 4082 catch (const std::invalid_argument& e) 4083 { 4084 EXPECT_STREQ(e.what(), "Element is not an array"); 4085 } 4086 } 4087 4088 TEST(ConfigFileParserTests, ParseRoot) 4089 { 4090 // Test where works: Only required properties specified 4091 { 4092 const json element = R"( 4093 { 4094 "chassis": [ 4095 { "number": 1, "inventory_path": "system/chassis" } 4096 ] 4097 } 4098 )"_json; 4099 std::vector<std::unique_ptr<Rule>> rules{}; 4100 std::vector<std::unique_ptr<Chassis>> chassis{}; 4101 std::tie(rules, chassis) = parseRoot(element); 4102 EXPECT_EQ(rules.size(), 0); 4103 EXPECT_EQ(chassis.size(), 1); 4104 } 4105 4106 // Test where works: All properties specified 4107 { 4108 const json element = R"( 4109 { 4110 "comments": [ "Config file for a FooBar one-chassis system" ], 4111 "rules": [ 4112 { 4113 "id": "set_voltage_rule", 4114 "actions": [ 4115 { "pmbus_write_vout_command": { "format": "linear" } } 4116 ] 4117 } 4118 ], 4119 "chassis": [ 4120 { "number": 1, "inventory_path": "system/chassis1" }, 4121 { "number": 3, "inventory_path": "system/chassis3" } 4122 ] 4123 } 4124 )"_json; 4125 std::vector<std::unique_ptr<Rule>> rules{}; 4126 std::vector<std::unique_ptr<Chassis>> chassis{}; 4127 std::tie(rules, chassis) = parseRoot(element); 4128 EXPECT_EQ(rules.size(), 1); 4129 EXPECT_EQ(chassis.size(), 2); 4130 } 4131 4132 // Test where fails: Element is not an object 4133 try 4134 { 4135 const json element = R"( [ "0xFF", "0x01" ] )"_json; 4136 parseRoot(element); 4137 ADD_FAILURE() << "Should not have reached this line."; 4138 } 4139 catch (const std::invalid_argument& e) 4140 { 4141 EXPECT_STREQ(e.what(), "Element is not an object"); 4142 } 4143 4144 // Test where fails: chassis property not specified 4145 try 4146 { 4147 const json element = R"( 4148 { 4149 "rules": [ 4150 { 4151 "id": "set_voltage_rule", 4152 "actions": [ 4153 { "pmbus_write_vout_command": { "format": "linear" } } 4154 ] 4155 } 4156 ] 4157 } 4158 )"_json; 4159 parseRoot(element); 4160 ADD_FAILURE() << "Should not have reached this line."; 4161 } 4162 catch (const std::invalid_argument& e) 4163 { 4164 EXPECT_STREQ(e.what(), "Required property missing: chassis"); 4165 } 4166 4167 // Test where fails: Invalid property specified 4168 try 4169 { 4170 const json element = R"( 4171 { 4172 "remarks": [ "Config file for a FooBar one-chassis system" ], 4173 "chassis": [ 4174 { "number": 1, "inventory_path": "system/chassis" } 4175 ] 4176 } 4177 )"_json; 4178 parseRoot(element); 4179 ADD_FAILURE() << "Should not have reached this line."; 4180 } 4181 catch (const std::invalid_argument& e) 4182 { 4183 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4184 } 4185 } 4186 4187 TEST(ConfigFileParserTests, ParseRule) 4188 { 4189 // Test where works: comments property specified 4190 { 4191 const json element = R"( 4192 { 4193 "comments": [ "Set voltage rule" ], 4194 "id": "set_voltage_rule", 4195 "actions": [ 4196 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4197 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 4198 ] 4199 } 4200 )"_json; 4201 std::unique_ptr<Rule> rule = parseRule(element); 4202 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 4203 EXPECT_EQ(rule->getActions().size(), 2); 4204 } 4205 4206 // Test where works: comments property not specified 4207 { 4208 const json element = R"( 4209 { 4210 "id": "set_voltage_rule", 4211 "actions": [ 4212 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4213 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }, 4214 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } } 4215 ] 4216 } 4217 )"_json; 4218 std::unique_ptr<Rule> rule = parseRule(element); 4219 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 4220 EXPECT_EQ(rule->getActions().size(), 3); 4221 } 4222 4223 // Test where fails: Element is not an object 4224 try 4225 { 4226 const json element = R"( [ "0xFF", "0x01" ] )"_json; 4227 parseRule(element); 4228 ADD_FAILURE() << "Should not have reached this line."; 4229 } 4230 catch (const std::invalid_argument& e) 4231 { 4232 EXPECT_STREQ(e.what(), "Element is not an object"); 4233 } 4234 4235 // Test where fails: id property not specified 4236 try 4237 { 4238 const json element = R"( 4239 { 4240 "actions": [ 4241 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4242 ] 4243 } 4244 )"_json; 4245 parseRule(element); 4246 ADD_FAILURE() << "Should not have reached this line."; 4247 } 4248 catch (const std::invalid_argument& e) 4249 { 4250 EXPECT_STREQ(e.what(), "Required property missing: id"); 4251 } 4252 4253 // Test where fails: id property is invalid 4254 try 4255 { 4256 const json element = R"( 4257 { 4258 "id": "", 4259 "actions": [ 4260 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4261 ] 4262 } 4263 )"_json; 4264 parseRule(element); 4265 ADD_FAILURE() << "Should not have reached this line."; 4266 } 4267 catch (const std::invalid_argument& e) 4268 { 4269 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4270 } 4271 4272 // Test where fails: actions property not specified 4273 try 4274 { 4275 const json element = R"( 4276 { 4277 "comments": [ "Set voltage rule" ], 4278 "id": "set_voltage_rule" 4279 } 4280 )"_json; 4281 parseRule(element); 4282 ADD_FAILURE() << "Should not have reached this line."; 4283 } 4284 catch (const std::invalid_argument& e) 4285 { 4286 EXPECT_STREQ(e.what(), "Required property missing: actions"); 4287 } 4288 4289 // Test where fails: actions property is invalid 4290 try 4291 { 4292 const json element = R"( 4293 { 4294 "id": "set_voltage_rule", 4295 "actions": true 4296 } 4297 )"_json; 4298 parseRule(element); 4299 ADD_FAILURE() << "Should not have reached this line."; 4300 } 4301 catch (const std::invalid_argument& e) 4302 { 4303 EXPECT_STREQ(e.what(), "Element is not an array"); 4304 } 4305 4306 // Test where fails: Invalid property specified 4307 try 4308 { 4309 const json element = R"( 4310 { 4311 "remarks": [ "Set voltage rule" ], 4312 "id": "set_voltage_rule", 4313 "actions": [ 4314 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4315 ] 4316 } 4317 )"_json; 4318 parseRule(element); 4319 ADD_FAILURE() << "Should not have reached this line."; 4320 } 4321 catch (const std::invalid_argument& e) 4322 { 4323 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4324 } 4325 } 4326 4327 TEST(ConfigFileParserTests, ParseRuleArray) 4328 { 4329 // Test where works 4330 { 4331 const json element = R"( 4332 [ 4333 { 4334 "id": "set_voltage_rule1", 4335 "actions": [ 4336 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4337 ] 4338 }, 4339 { 4340 "id": "set_voltage_rule2", 4341 "actions": [ 4342 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4343 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } } 4344 ] 4345 } 4346 ] 4347 )"_json; 4348 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element); 4349 EXPECT_EQ(rules.size(), 2); 4350 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 4351 EXPECT_EQ(rules[0]->getActions().size(), 1); 4352 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 4353 EXPECT_EQ(rules[1]->getActions().size(), 2); 4354 } 4355 4356 // Test where fails: Element is not an array 4357 try 4358 { 4359 const json element = R"( { "id": "set_voltage_rule" } )"_json; 4360 parseRuleArray(element); 4361 ADD_FAILURE() << "Should not have reached this line."; 4362 } 4363 catch (const std::invalid_argument& e) 4364 { 4365 EXPECT_STREQ(e.what(), "Element is not an array"); 4366 } 4367 } 4368 4369 TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty) 4370 { 4371 // Test where works: actions specified 4372 { 4373 const json element = R"( 4374 { 4375 "actions": [ 4376 { "pmbus_write_vout_command": { "format": "linear" } }, 4377 { "run_rule": "set_voltage_rule" } 4378 ] 4379 } 4380 )"_json; 4381 std::vector<std::unique_ptr<Action>> actions = 4382 parseRuleIDOrActionsProperty(element); 4383 EXPECT_EQ(actions.size(), 2); 4384 } 4385 4386 // Test where works: rule_id specified 4387 { 4388 const json element = R"( 4389 { 4390 "rule_id": "set_voltage_rule" 4391 } 4392 )"_json; 4393 std::vector<std::unique_ptr<Action>> actions = 4394 parseRuleIDOrActionsProperty(element); 4395 EXPECT_EQ(actions.size(), 1); 4396 } 4397 4398 // Test where fails: Element is not an object 4399 try 4400 { 4401 const json element = R"( [ "foo", "bar" ] )"_json; 4402 parseRuleIDOrActionsProperty(element); 4403 ADD_FAILURE() << "Should not have reached this line."; 4404 } 4405 catch (const std::invalid_argument& e) 4406 { 4407 EXPECT_STREQ(e.what(), "Element is not an object"); 4408 } 4409 4410 // Test where fails: rule_id is invalid 4411 try 4412 { 4413 const json element = R"( 4414 { "rule_id": 1 } 4415 )"_json; 4416 parseRuleIDOrActionsProperty(element); 4417 ADD_FAILURE() << "Should not have reached this line."; 4418 } 4419 catch (const std::invalid_argument& e) 4420 { 4421 EXPECT_STREQ(e.what(), "Element is not a string"); 4422 } 4423 4424 // Test where fails: actions is invalid 4425 try 4426 { 4427 const json element = R"( 4428 { "actions": 1 } 4429 )"_json; 4430 parseRuleIDOrActionsProperty(element); 4431 ADD_FAILURE() << "Should not have reached this line."; 4432 } 4433 catch (const std::invalid_argument& e) 4434 { 4435 EXPECT_STREQ(e.what(), "Element is not an array"); 4436 } 4437 4438 // Test where fails: Neither rule_id nor actions specified 4439 try 4440 { 4441 const json element = R"( 4442 { 4443 "volts": 1.03 4444 } 4445 )"_json; 4446 parseRuleIDOrActionsProperty(element); 4447 ADD_FAILURE() << "Should not have reached this line."; 4448 } 4449 catch (const std::invalid_argument& e) 4450 { 4451 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4452 "either rule_id or actions"); 4453 } 4454 4455 // Test where fails: Both rule_id and actions specified 4456 try 4457 { 4458 const json element = R"( 4459 { 4460 "volts": 1.03, 4461 "rule_id": "set_voltage_rule", 4462 "actions": [ 4463 { 4464 "pmbus_write_vout_command": { 4465 "format": "linear" 4466 } 4467 } 4468 ] 4469 } 4470 )"_json; 4471 parseRuleIDOrActionsProperty(element); 4472 ADD_FAILURE() << "Should not have reached this line."; 4473 } 4474 catch (const std::invalid_argument& e) 4475 { 4476 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4477 "either rule_id or actions"); 4478 } 4479 } 4480 4481 TEST(ConfigFileParserTests, ParseRunRule) 4482 { 4483 // Test where works 4484 { 4485 const json element = "vdd_regulator"; 4486 std::unique_ptr<RunRuleAction> action = parseRunRule(element); 4487 EXPECT_EQ(action->getRuleID(), "vdd_regulator"); 4488 } 4489 4490 // Test where fails: Element is not a string 4491 try 4492 { 4493 const json element = 1; 4494 parseRunRule(element); 4495 ADD_FAILURE() << "Should not have reached this line."; 4496 } 4497 catch (const std::invalid_argument& e) 4498 { 4499 EXPECT_STREQ(e.what(), "Element is not a string"); 4500 } 4501 4502 // Test where fails: Empty string 4503 try 4504 { 4505 const json element = ""; 4506 parseRunRule(element); 4507 ADD_FAILURE() << "Should not have reached this line."; 4508 } 4509 catch (const std::invalid_argument& e) 4510 { 4511 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4512 } 4513 } 4514 4515 TEST(ConfigFileParserTests, ParseSensorDataFormat) 4516 { 4517 // Test where works: linear_11 4518 { 4519 const json element = "linear_11"; 4520 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element); 4521 pmbus_utils::SensorDataFormat format = 4522 pmbus_utils::SensorDataFormat::linear_11; 4523 EXPECT_EQ(value, format); 4524 } 4525 4526 // Test where works: linear_16 4527 { 4528 const json element = "linear_16"; 4529 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element); 4530 pmbus_utils::SensorDataFormat format = 4531 pmbus_utils::SensorDataFormat::linear_16; 4532 EXPECT_EQ(value, format); 4533 } 4534 4535 // Test where fails: Element is not a sensor data format 4536 try 4537 { 4538 const json element = "foo"; 4539 parseSensorDataFormat(element); 4540 ADD_FAILURE() << "Should not have reached this line."; 4541 } 4542 catch (const std::invalid_argument& e) 4543 { 4544 EXPECT_STREQ(e.what(), "Element is not a sensor data format"); 4545 } 4546 4547 // Test where fails: Element is not a string 4548 try 4549 { 4550 const json element = R"( { "foo": "bar" } )"_json; 4551 parseSensorDataFormat(element); 4552 ADD_FAILURE() << "Should not have reached this line."; 4553 } 4554 catch (const std::invalid_argument& e) 4555 { 4556 EXPECT_STREQ(e.what(), "Element is not a string"); 4557 } 4558 } 4559 4560 TEST(ConfigFileParserTests, ParseSensorMonitoring) 4561 { 4562 // Test where works: actions property specified 4563 { 4564 const json element = R"( 4565 { 4566 "actions": [ 4567 { "run_rule": "read_sensors_rule" } 4568 ] 4569 } 4570 )"_json; 4571 std::unique_ptr<SensorMonitoring> sensorMonitoring = 4572 parseSensorMonitoring(element); 4573 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 4574 } 4575 4576 // Test where works: rule_id property specified 4577 { 4578 const json element = R"( 4579 { 4580 "comments": [ "comments property" ], 4581 "rule_id": "set_voltage_rule" 4582 } 4583 )"_json; 4584 std::unique_ptr<SensorMonitoring> sensorMonitoring = 4585 parseSensorMonitoring(element); 4586 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 4587 } 4588 4589 // Test where fails: actions object is invalid 4590 try 4591 { 4592 const json element = R"( 4593 { 4594 "actions": 1 4595 } 4596 )"_json; 4597 parseSensorMonitoring(element); 4598 ADD_FAILURE() << "Should not have reached this line."; 4599 } 4600 catch (const std::invalid_argument& e) 4601 { 4602 EXPECT_STREQ(e.what(), "Element is not an array"); 4603 } 4604 4605 // Test where fails: rule_id value is invalid 4606 try 4607 { 4608 const json element = R"( 4609 { 4610 "rule_id": 1 4611 } 4612 )"_json; 4613 parseSensorMonitoring(element); 4614 ADD_FAILURE() << "Should not have reached this line."; 4615 } 4616 catch (const std::invalid_argument& e) 4617 { 4618 EXPECT_STREQ(e.what(), "Element is not a string"); 4619 } 4620 4621 // Test where fails: Required actions or rule_id property not specified 4622 try 4623 { 4624 const json element = R"( 4625 { 4626 "comments": [ "comments property" ] 4627 } 4628 )"_json; 4629 parseSensorMonitoring(element); 4630 ADD_FAILURE() << "Should not have reached this line."; 4631 } 4632 catch (const std::invalid_argument& e) 4633 { 4634 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4635 "either rule_id or actions"); 4636 } 4637 4638 // Test where fails: Required actions or rule_id property both specified 4639 try 4640 { 4641 const json element = R"( 4642 { 4643 "rule_id": "set_voltage_rule", 4644 "actions": [ 4645 { "run_rule": "read_sensors_rule" } 4646 ] 4647 } 4648 )"_json; 4649 parseSensorMonitoring(element); 4650 ADD_FAILURE() << "Should not have reached this line."; 4651 } 4652 catch (const std::invalid_argument& e) 4653 { 4654 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4655 "either rule_id or actions"); 4656 } 4657 4658 // Test where fails: Element is not an object 4659 try 4660 { 4661 const json element = R"( [ "foo", "bar" ] )"_json; 4662 parseSensorMonitoring(element); 4663 ADD_FAILURE() << "Should not have reached this line."; 4664 } 4665 catch (const std::invalid_argument& e) 4666 { 4667 EXPECT_STREQ(e.what(), "Element is not an object"); 4668 } 4669 4670 // Test where fails: Invalid property specified 4671 try 4672 { 4673 const json element = R"( 4674 { 4675 "foo": "bar", 4676 "actions": [ 4677 { "run_rule": "read_sensors_rule" } 4678 ] 4679 } 4680 )"_json; 4681 parseSensorMonitoring(element); 4682 ADD_FAILURE() << "Should not have reached this line."; 4683 } 4684 catch (const std::invalid_argument& e) 4685 { 4686 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4687 } 4688 } 4689 4690 TEST(ConfigFileParserTests, ParseSensorType) 4691 { 4692 // Test where works: iout 4693 { 4694 const json element = "iout"; 4695 SensorType type = parseSensorType(element); 4696 EXPECT_EQ(type, SensorType::iout); 4697 } 4698 4699 // Test where works: iout_peak 4700 { 4701 const json element = "iout_peak"; 4702 SensorType type = parseSensorType(element); 4703 EXPECT_EQ(type, SensorType::iout_peak); 4704 } 4705 4706 // Test where works: iout_valley 4707 { 4708 const json element = "iout_valley"; 4709 SensorType type = parseSensorType(element); 4710 EXPECT_EQ(type, SensorType::iout_valley); 4711 } 4712 4713 // Test where works: pout 4714 { 4715 const json element = "pout"; 4716 SensorType type = parseSensorType(element); 4717 EXPECT_EQ(type, SensorType::pout); 4718 } 4719 4720 // Test where works: temperature 4721 { 4722 const json element = "temperature"; 4723 SensorType type = parseSensorType(element); 4724 EXPECT_EQ(type, SensorType::temperature); 4725 } 4726 4727 // Test where works: temperature_peak 4728 { 4729 const json element = "temperature_peak"; 4730 SensorType type = parseSensorType(element); 4731 EXPECT_EQ(type, SensorType::temperature_peak); 4732 } 4733 4734 // Test where works: vout 4735 { 4736 const json element = "vout"; 4737 SensorType type = parseSensorType(element); 4738 EXPECT_EQ(type, SensorType::vout); 4739 } 4740 4741 // Test where works: vout_peak 4742 { 4743 const json element = "vout_peak"; 4744 SensorType type = parseSensorType(element); 4745 EXPECT_EQ(type, SensorType::vout_peak); 4746 } 4747 4748 // Test where works: vout_valley 4749 { 4750 const json element = "vout_valley"; 4751 SensorType type = parseSensorType(element); 4752 EXPECT_EQ(type, SensorType::vout_valley); 4753 } 4754 4755 // Test where fails: Element is not a sensor type 4756 try 4757 { 4758 const json element = "foo"; 4759 parseSensorType(element); 4760 ADD_FAILURE() << "Should not have reached this line."; 4761 } 4762 catch (const std::invalid_argument& e) 4763 { 4764 EXPECT_STREQ(e.what(), "Element is not a sensor type"); 4765 } 4766 4767 // Test where fails: Element is not a string 4768 try 4769 { 4770 const json element = R"( { "foo": "bar" } )"_json; 4771 parseSensorType(element); 4772 ADD_FAILURE() << "Should not have reached this line."; 4773 } 4774 catch (const std::invalid_argument& e) 4775 { 4776 EXPECT_STREQ(e.what(), "Element is not a string"); 4777 } 4778 } 4779 4780 TEST(ConfigFileParserTests, ParseSetDevice) 4781 { 4782 // Test where works 4783 { 4784 const json element = "regulator1"; 4785 std::unique_ptr<SetDeviceAction> action = parseSetDevice(element); 4786 EXPECT_EQ(action->getDeviceID(), "regulator1"); 4787 } 4788 4789 // Test where fails: Element is not a string 4790 try 4791 { 4792 const json element = 1; 4793 parseSetDevice(element); 4794 ADD_FAILURE() << "Should not have reached this line."; 4795 } 4796 catch (const std::invalid_argument& e) 4797 { 4798 EXPECT_STREQ(e.what(), "Element is not a string"); 4799 } 4800 4801 // Test where fails: Empty string 4802 try 4803 { 4804 const json element = ""; 4805 parseSetDevice(element); 4806 ADD_FAILURE() << "Should not have reached this line."; 4807 } 4808 catch (const std::invalid_argument& e) 4809 { 4810 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4811 } 4812 } 4813 4814 TEST(ConfigFileParserTests, ParseVoutDataFormat) 4815 { 4816 // Test where works: linear 4817 { 4818 const json element = "linear"; 4819 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4820 pmbus_utils::VoutDataFormat format = 4821 pmbus_utils::VoutDataFormat::linear; 4822 EXPECT_EQ(value, format); 4823 } 4824 4825 // Test where works: vid 4826 { 4827 const json element = "vid"; 4828 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4829 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::vid; 4830 EXPECT_EQ(value, format); 4831 } 4832 4833 // Test where works: direct 4834 { 4835 const json element = "direct"; 4836 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4837 pmbus_utils::VoutDataFormat format = 4838 pmbus_utils::VoutDataFormat::direct; 4839 EXPECT_EQ(value, format); 4840 } 4841 4842 // Test where works: ieee 4843 { 4844 const json element = "ieee"; 4845 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4846 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::ieee; 4847 EXPECT_EQ(value, format); 4848 } 4849 4850 // Test where fails: Element is not a vout data format 4851 try 4852 { 4853 const json element = "foo"; 4854 parseVoutDataFormat(element); 4855 ADD_FAILURE() << "Should not have reached this line."; 4856 } 4857 catch (const std::invalid_argument& e) 4858 { 4859 EXPECT_STREQ(e.what(), "Element is not a vout data format"); 4860 } 4861 4862 // Test where fails: Element is not a string 4863 try 4864 { 4865 const json element = R"( { "foo": "bar" } )"_json; 4866 parseVoutDataFormat(element); 4867 ADD_FAILURE() << "Should not have reached this line."; 4868 } 4869 catch (const std::invalid_argument& e) 4870 { 4871 EXPECT_STREQ(e.what(), "Element is not a string"); 4872 } 4873 } 4874