regulators: Implements support for rail
Enhance the configuration file parser to support the rail element.
Signed-off-by: Bob King <Bob_King@wistron.com>
Change-Id: Id10809cac4271295c5eb3bd318be775e1d470286
diff --git a/phosphor-regulators/src/config_file_parser.cpp b/phosphor-regulators/src/config_file_parser.cpp
index ce95d2d..cc96545 100644
--- a/phosphor-regulators/src/config_file_parser.cpp
+++ b/phosphor-regulators/src/config_file_parser.cpp
@@ -519,15 +519,55 @@
exponent, isVerified);
}
+std::unique_ptr<Rail> parseRail(const json& element)
+{
+ verifyIsObject(element);
+ unsigned int propertyCount{0};
+
+ // Optional comments property; value not stored
+ if (element.contains("comments"))
+ {
+ ++propertyCount;
+ }
+
+ // Required id property
+ const json& idElement = getRequiredProperty(element, "id");
+ std::string id = parseString(idElement);
+ ++propertyCount;
+
+ // Optional configuration property
+ std::unique_ptr<Configuration> configuration{};
+ auto configurationIt = element.find("configuration");
+ if (configurationIt != element.end())
+ {
+ configuration = parseConfiguration(*configurationIt);
+ ++propertyCount;
+ }
+
+ // Optional sensor_monitoring property
+ std::unique_ptr<SensorMonitoring> sensorMonitoring{};
+ auto sensorMonitoringIt = element.find("sensor_monitoring");
+ if (sensorMonitoringIt != element.end())
+ {
+ sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
+ ++propertyCount;
+ }
+
+ // Verify no invalid properties exist
+ verifyPropertyCount(element, propertyCount);
+
+ return std::make_unique<Rail>(id, std::move(configuration),
+ std::move(sensorMonitoring));
+}
+
std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
{
verifyIsArray(element);
std::vector<std::unique_ptr<Rail>> rails;
- // TODO: Not implemented yet
- // for (auto& railElement : element)
- // {
- // rails.emplace_back(parseRail(railElement));
- // }
+ for (auto& railElement : element)
+ {
+ rails.emplace_back(parseRail(railElement));
+ }
return rails;
}
@@ -638,6 +678,28 @@
return std::make_unique<RunRuleAction>(ruleID);
}
+std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
+{
+ verifyIsObject(element);
+ unsigned int propertyCount{0};
+
+ // Optional comments property; value not stored
+ if (element.contains("comments"))
+ {
+ ++propertyCount;
+ }
+
+ // Required rule_id or actions property
+ std::vector<std::unique_ptr<Action>> actions{};
+ actions = parseRuleIDOrActionsProperty(element);
+ ++propertyCount;
+
+ // Verify no invalid properties exist
+ verifyPropertyCount(element, propertyCount);
+
+ return std::make_unique<SensorMonitoring>(std::move(actions));
+}
+
} // namespace internal
} // namespace phosphor::power::regulators::config_file_parser
diff --git a/phosphor-regulators/src/config_file_parser.hpp b/phosphor-regulators/src/config_file_parser.hpp
index 251f236..66c4c93 100644
--- a/phosphor-regulators/src/config_file_parser.hpp
+++ b/phosphor-regulators/src/config_file_parser.hpp
@@ -28,6 +28,7 @@
#include "rail.hpp"
#include "rule.hpp"
#include "run_rule_action.hpp"
+#include "sensor_monitoring.hpp"
#include <nlohmann/json.hpp>
@@ -397,6 +398,18 @@
parsePMBusWriteVoutCommand(const nlohmann::json& element);
/**
+ * Parses a JSON element containing a rail.
+ *
+ * Returns the corresponding C++ Rail object.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return Rail object
+ */
+std::unique_ptr<Rail> parseRail(const nlohmann::json& element);
+
+/**
* Parses a JSON element containing an array of rails.
*
* Returns the corresponding C++ Rail objects.
@@ -480,6 +493,19 @@
std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
/**
+ * Parses a JSON element containing a sensor monitoring operation.
+ *
+ * Returns the corresponding C++ SensorMonitoring object.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return SensorMonitoring object
+ */
+std::unique_ptr<SensorMonitoring>
+ parseSensorMonitoring(const nlohmann::json& element);
+
+/**
* Parses a JSON element containing a string.
*
* Returns the corresponding C++ string.
diff --git a/phosphor-regulators/test/config_file_parser_tests.cpp b/phosphor-regulators/test/config_file_parser_tests.cpp
index e848fd7..be8a4c8 100644
--- a/phosphor-regulators/test/config_file_parser_tests.cpp
+++ b/phosphor-regulators/test/config_file_parser_tests.cpp
@@ -29,6 +29,7 @@
#include "rail.hpp"
#include "rule.hpp"
#include "run_rule_action.hpp"
+#include "sensor_monitoring.hpp"
#include "tmp_file.hpp"
#include <sys/stat.h> // for chmod()
@@ -956,7 +957,7 @@
// Test where works: All properties specified
{
- // TODO : add rails and presence_detection properties
+ // TODO : add presence_detection property
const json element = R"(
{
"id": "vdd_regulator",
@@ -970,7 +971,13 @@
"configuration":
{
"rule_id": "configure_ir35221_rule"
- }
+ },
+ "rails":
+ [
+ {
+ "id": "vdd"
+ }
+ ]
}
)"_json;
std::unique_ptr<Device> device = parseDevice(element);
@@ -980,7 +987,41 @@
EXPECT_NE(&(device->getI2CInterface()), nullptr);
// EXPECT_NE(device->getPresenceDetection(), nullptr);
EXPECT_NE(device->getConfiguration(), nullptr);
- // EXPECT_NE(device->getRails().size(), 0);
+ EXPECT_EQ(device->getRails().size(), 1);
+ }
+
+ // Test where fails: rails property exists and is_regulator is false
+ try
+ {
+ const json element = R"(
+ {
+ "id": "vdd_regulator",
+ "is_regulator": false,
+ "fru": "/system/chassis/motherboard/regulator2",
+ "i2c_interface":
+ {
+ "bus": 1,
+ "address": "0x70"
+ },
+ "configuration":
+ {
+ "rule_id": "configure_ir35221_rule"
+ },
+ "rails":
+ [
+ {
+ "id": "vdd"
+ }
+ ]
+ }
+ )"_json;
+ parseDevice(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(),
+ "Invalid rails property when is_regulator is false");
}
// Test where fails: id value is invalid
@@ -2076,6 +2117,209 @@
}
}
+TEST(ConfigFileParserTests, ParseRail)
+{
+ // Test where works: Only required properties specified
+ {
+ const json element = R"(
+ {
+ "id": "vdd"
+ }
+ )"_json;
+ std::unique_ptr<Rail> rail = parseRail(element);
+ EXPECT_EQ(rail->getID(), "vdd");
+ EXPECT_EQ(rail->getConfiguration(), nullptr);
+ EXPECT_EQ(rail->getSensorMonitoring(), nullptr);
+ }
+
+ // Test where works: All properties specified
+ {
+ const json element = R"(
+ {
+ "comments": [ "comments property" ],
+ "id": "vdd",
+ "configuration": {
+ "volts": 1.1,
+ "actions": [
+ {
+ "pmbus_write_vout_command": {
+ "format": "linear"
+ }
+ }
+ ]
+ },
+ "sensor_monitoring": {
+ "actions": [
+ { "run_rule": "read_sensors_rule" }
+ ]
+ }
+ }
+ )"_json;
+ std::unique_ptr<Rail> rail = parseRail(element);
+ EXPECT_EQ(rail->getID(), "vdd");
+ EXPECT_NE(rail->getConfiguration(), nullptr);
+ EXPECT_NE(rail->getSensorMonitoring(), nullptr);
+ }
+
+ // Test where fails: id property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "configuration": {
+ "volts": 1.1,
+ "actions": [
+ {
+ "pmbus_write_vout_command": {
+ "format": "linear"
+ }
+ }
+ ]
+ }
+ }
+ )"_json;
+ parseRail(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Required property missing: id");
+ }
+
+ // Test where fails: id property is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "id": "",
+ "configuration": {
+ "volts": 1.1,
+ "actions": [
+ {
+ "pmbus_write_vout_command": {
+ "format": "linear"
+ }
+ }
+ ]
+ }
+ }
+ )"_json;
+ parseRail(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element contains an empty string");
+ }
+
+ // Test where fails: Element is not an object
+ try
+ {
+ const json element = R"( [ "0xFF", "0x01" ] )"_json;
+ parseRail(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an object");
+ }
+
+ // Test where fails: configuration value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "id": "vdd",
+ "configuration": "config"
+ }
+ )"_json;
+ parseRail(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an object");
+ }
+
+ // Test where fails: sensor_monitoring value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "comments": [ "comments property" ],
+ "id": "vdd",
+ "configuration": {
+ "volts": 1.1,
+ "actions": [
+ {
+ "pmbus_write_vout_command": {
+ "format": "linear"
+ }
+ }
+ ]
+ },
+ "sensor_monitoring": 1
+ }
+ )"_json;
+ parseRail(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an object");
+ }
+
+ // Test where fails: Invalid property specified
+ try
+ {
+ const json element = R"(
+ {
+ "id": "vdd",
+ "foo" : true
+ }
+ )"_json;
+ parseRail(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element contains an invalid property");
+ }
+}
+
+TEST(ConfigFileParserTests, ParseRailArray)
+{
+ // Test where works
+ {
+ const json element = R"(
+ [
+ { "id": "vdd" },
+ { "id": "vio" }
+ ]
+ )"_json;
+ std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
+ EXPECT_EQ(rails.size(), 2);
+ EXPECT_EQ(rails[0]->getID(), "vdd");
+ EXPECT_EQ(rails[1]->getID(), "vio");
+ }
+
+ // Test where fails: Element is not an array
+ try
+ {
+ const json element = R"(
+ {
+ "foo": "bar"
+ }
+ )"_json;
+ parseRailArray(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an array");
+ }
+}
+
TEST(ConfigFileParserTests, ParseRoot)
{
// Test where works: Only required properties specified
@@ -2503,6 +2747,136 @@
}
}
+TEST(ConfigFileParserTests, ParseSensorMonitoring)
+{
+ // Test where works: actions property specified
+ {
+ const json element = R"(
+ {
+ "actions": [
+ { "run_rule": "read_sensors_rule" }
+ ]
+ }
+ )"_json;
+ std::unique_ptr<SensorMonitoring> sensorMonitoring =
+ parseSensorMonitoring(element);
+ EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
+ }
+
+ // Test where works: rule_id property specified
+ {
+ const json element = R"(
+ {
+ "comments": [ "comments property" ],
+ "rule_id": "set_voltage_rule"
+ }
+ )"_json;
+ std::unique_ptr<SensorMonitoring> sensorMonitoring =
+ parseSensorMonitoring(element);
+ EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
+ }
+
+ // Test where fails: actions object is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "actions": 1
+ }
+ )"_json;
+ parseSensorMonitoring(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an array");
+ }
+
+ // Test where fails: rule_id value is invalid
+ try
+ {
+ const json element = R"(
+ {
+ "rule_id": 1
+ }
+ )"_json;
+ parseSensorMonitoring(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a string");
+ }
+
+ // Test where fails: Required actions or rule_id property not specified
+ try
+ {
+ const json element = R"(
+ {
+ "comments": [ "comments property" ]
+ }
+ )"_json;
+ parseSensorMonitoring(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
+ "either rule_id or actions");
+ }
+
+ // Test where fails: Required actions or rule_id property both specified
+ try
+ {
+ const json element = R"(
+ {
+ "rule_id": "set_voltage_rule",
+ "actions": [
+ { "run_rule": "read_sensors_rule" }
+ ]
+ }
+ )"_json;
+ parseSensorMonitoring(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
+ "either rule_id or actions");
+ }
+
+ // Test where fails: Element is not an object
+ try
+ {
+ const json element = R"( [ "foo", "bar" ] )"_json;
+ parseSensorMonitoring(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an object");
+ }
+
+ // Test where fails: Invalid property specified
+ try
+ {
+ const json element = R"(
+ {
+ "foo": "bar",
+ "actions": [
+ { "run_rule": "read_sensors_rule" }
+ ]
+ }
+ )"_json;
+ parseSensorMonitoring(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element contains an invalid property");
+ }
+}
+
TEST(ConfigFileParserTests, ParseString)
{
// Test where works: Empty string