diff options
| author | Patrick Venture <venture@google.com> | 2019-02-11 12:03:30 -0800 |
|---|---|---|
| committer | Patrick Venture <venture@google.com> | 2019-02-11 14:36:32 -0800 |
| commit | 5426c3493733aea04415f4e820dbfbae10845243 (patch) | |
| tree | 9662cf7caef1cd37875f919f7fc94293bad6d824 | |
| parent | 81cef9143d2d6451f1a70738f68b61a2350323ff (diff) | |
| download | phosphor-pid-control-5426c3493733aea04415f4e820dbfbae10845243.tar.gz phosphor-pid-control-5426c3493733aea04415f4e820dbfbae10845243.zip | |
add json verification for configurations
Add json verificiation for configurations. A configuration is lightly
validated.
Change-Id: I42361daf6ad21d3480e92c3808f5fc8ab8318e0b
Signed-off-by: Patrick Venture <venture@google.com>
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | build/buildjson.cpp | 64 | ||||
| -rw-r--r-- | build/buildjson.hpp | 27 | ||||
| -rw-r--r-- | test/Makefile.am | 5 | ||||
| -rw-r--r-- | test/json_parse_unittest.cpp | 154 |
5 files changed, 250 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index cce4f4c..c227281 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,6 +78,7 @@ libswampd_la_SOURCES = \ pid/util.cpp \ pid/pidthread.cpp \ threads/busthread.cpp \ + build/buildjson.cpp \ experiments/drive.cpp \ $(BUILT_SOURCES) diff --git a/build/buildjson.cpp b/build/buildjson.cpp new file mode 100644 index 0000000..a5ae502 --- /dev/null +++ b/build/buildjson.cpp @@ -0,0 +1,64 @@ +#include "build/buildjson.hpp" + +#include "errors/exception.hpp" + +#include <fstream> +#include <nlohmann/json.hpp> + +using json = nlohmann::json; + +void validateJson(const json& data) +{ + if (data.count("sensors") != 1) + { + throw ConfigurationException( + "KeyError: 'sensors' not found (or found repeatedly)"); + } + + if (data["sensors"].size() == 0) + { + throw ConfigurationException( + "Invalid Configuration: At least one sensor required"); + } + + if (data.count("zones") != 1) + { + throw ConfigurationException( + "KeyError: 'zones' not found (or found repeatedly)"); + } + + for (const auto& zone : data["zones"]) + { + if (zone.count("pids") != 1) + { + throw ConfigurationException( + "KeyError: should only have one 'pids' key per zone."); + } + + if (zone["pids"].size() == 0) + { + throw ConfigurationException( + "Invalid Configuration: must be at least one pid per zone."); + } + } +} + +json parseValidateJson(const std::string& path) +{ + std::ifstream jsonFile(path); + if (!jsonFile.is_open()) + { + throw ConfigurationException("Unable to open json file"); + } + + auto data = json::parse(jsonFile, nullptr, false); + if (data.is_discarded()) + { + throw ConfigurationException("Invalid json - parse failed"); + } + + /* Check the data. */ + validateJson(data); + + return data; +} diff --git a/build/buildjson.hpp b/build/buildjson.hpp new file mode 100644 index 0000000..afc90df --- /dev/null +++ b/build/buildjson.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <nlohmann/json.hpp> +#include <string> + +using json = nlohmann::json; + +/** + * Given json data, validate the minimum. + * The json data must be valid, and must contain two keys: + * sensors, and zones. + * + * @param[in] data - the json data. + * @return nothing - throws exceptions on invalid bits. + */ +void validateJson(const json& data); + +/** + * Given a json configuration file, parse it. + * + * There must be at least one sensor, and one zone. + * That one zone must contain at least one PID. + * + * @param[in] path - path to the configuration + * @return the json data. + */ +json parseValidateJson(const std::string& path); diff --git a/test/Makefile.am b/test/Makefile.am index 5375eb4..04cf2df 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -18,7 +18,7 @@ check_PROGRAMS = sensor_manager_unittest sensor_pluggable_unittest \ pid_thermalcontroller_unittest pid_fancontroller_unittest \ pid_stepwisecontroller_unittest \ dbus_passive_unittest dbus_active_unittest \ - sensors_json_unittest pid_json_unittest + sensors_json_unittest pid_json_unittest json_parse_unittest TESTS = $(check_PROGRAMS) # Until libconfig is mocked out or replaced, include it. @@ -65,3 +65,6 @@ sensors_json_unittest_LDADD = $(top_builddir)/sensors/buildjson.o pid_json_unittest_SOURCES = pid_json_unittest.cpp pid_json_unittest_LDADD = $(top_builddir)/pid/buildjson.o + +json_parse_unittest_SOURCES = json_parse_unittest.cpp +json_parse_unittest_LDADD = $(top_builddir)/build/buildjson.o diff --git a/test/json_parse_unittest.cpp b/test/json_parse_unittest.cpp new file mode 100644 index 0000000..7d3d449 --- /dev/null +++ b/test/json_parse_unittest.cpp @@ -0,0 +1,154 @@ +#include "build/buildjson.hpp" +#include "errors/exception.hpp" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +TEST(ConfigurationVerificationTest, VerifyHappy) +{ + /* Verify a happy configuration throws no exceptions. */ + auto j2 = R"( + { + "sensors": [{ + "name": "fan1", + "type": "fan", + "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1" + }], + "zones": [{ + "id": 1, + "minThermalRpm": 3000.0, + "failsafePercent": 75.0, + "pids": [{ + "name": "fan1-5", + "type": "fan", + "inputs": ["fan1", "fan5"], + "setpoint": 90.0, + "pid": { + "samplePeriod": 0.1, + "proportionalCoeff": 0.0, + "integralCoeff": 0.0, + "feedFwdOffOffsetCoeff": 0.0, + "feedFwdGainCoeff": 0.010, + "integralLimit_min": 0.0, + "integralLimit_max": 0.0, + "outLim_min": 30.0, + "outLim_max": 100.0, + "slewNeg": 0.0, + "slewPos": 0.0 + } + }] + }] + } + )"_json; + + validateJson(j2); +} + +TEST(ConfigurationVerificationTest, VerifyNoSensorKey) +{ + /* Verify the sensors key must be present. */ + auto j2 = R"( + { + "zones": [{ + "id": 1, + "minThermalRpm": 3000.0, + "failsafePercent": 75.0, + "pids": [{ + "name": "fan1-5", + "type": "fan", + "inputs": ["fan1", "fan5"], + "setpoint": 90.0, + "pid": { + "samplePeriod": 0.1, + "proportionalCoeff": 0.0, + "integralCoeff": 0.0, + "feedFwdOffOffsetCoeff": 0.0, + "feedFwdGainCoeff": 0.010, + "integralLimit_min": 0.0, + "integralLimit_max": 0.0, + "outLim_min": 30.0, + "outLim_max": 100.0, + "slewNeg": 0.0, + "slewPos": 0.0 + } + }] + }] + } + )"_json; + + EXPECT_THROW(validateJson(j2), ConfigurationException); +} + +TEST(ConfigurationVerificationTest, VerifyNoZoneKey) +{ + /* Verify the zones key must be present. */ + auto j2 = R"( + { + "sensors": [{ + "name": "fan1", + "type": "fan", + "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1" + }] + } + )"_json; + + EXPECT_THROW(validateJson(j2), ConfigurationException); +} + +TEST(ConfigurationVerificationTest, VerifyNoSensor) +{ + /* Verify that there needs to be at least one sensor in the sensors key. */ + auto j2 = R"( + { + "sensors": [], + "zones": [{ + "id": 1, + "minThermalRpm": 3000.0, + "failsafePercent": 75.0, + "pids": [{ + "name": "fan1-5", + "type": "fan", + "inputs": ["fan1", "fan5"], + "setpoint": 90.0, + "pid": { + "samplePeriod": 0.1, + "proportionalCoeff": 0.0, + "integralCoeff": 0.0, + "feedFwdOffOffsetCoeff": 0.0, + "feedFwdGainCoeff": 0.010, + "integralLimit_min": 0.0, + "integralLimit_max": 0.0, + "outLim_min": 30.0, + "outLim_max": 100.0, + "slewNeg": 0.0, + "slewPos": 0.0 + } + }] + }] + } + )"_json; + + EXPECT_THROW(validateJson(j2), ConfigurationException); +} + +TEST(ConfigurationVerificationTest, VerifyNoPidInZone) +{ + /* Verify that there needs to be at least one PID in the zone. */ + auto j2 = R"( + { + "sensors": [{ + "name": "fan1", + "type": "fan", + "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1" + }], + "zones": [{ + "id": 1, + "minThermalRpm": 3000.0, + "failsafePercent": 75.0, + "pids": [] + }] + } + )"_json; + + EXPECT_THROW(validateJson(j2), ConfigurationException); +} |

