Repository: nifi-minifi-cpp Updated Branches: refs/heads/master b3818fff6 -> a507e3cc6
MINIFICPP-467 Added validation of mutually-exclusive properties This closes #349. Signed-off-by: Aldrin Piri <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/commit/a507e3cc Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/tree/a507e3cc Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/diff/a507e3cc Branch: refs/heads/master Commit: a507e3cc6189d872cac5085f6afbe4f0c8ce008e Parents: b3818ff Author: Andrew I. Christianson <[email protected]> Authored: Thu May 31 11:32:25 2018 -0400 Committer: Aldrin Piri <[email protected]> Committed: Tue Jul 24 17:57:30 2018 -0400 ---------------------------------------------------------------------- libminifi/include/core/yaml/YamlConfiguration.h | 7 +++ libminifi/src/core/yaml/YamlConfiguration.cpp | 35 ++++++++++++ libminifi/test/unit/YamlConfigurationTests.cpp | 56 ++++++++++++++++++++ 3 files changed, 98 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a507e3cc/libminifi/include/core/yaml/YamlConfiguration.h ---------------------------------------------------------------------- diff --git a/libminifi/include/core/yaml/YamlConfiguration.h b/libminifi/include/core/yaml/YamlConfiguration.h index 09edd26..6e22fe3 100644 --- a/libminifi/include/core/yaml/YamlConfiguration.h +++ b/libminifi/include/core/yaml/YamlConfiguration.h @@ -43,6 +43,13 @@ namespace core { #define CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY_V3 "Remote Process Groups" #define CONFIG_YAML_PROVENANCE_REPORT_KEY "Provenance Reporting" +#define YAML_CONFIGURATION_USE_REGEX + +// Disable regex in EL for incompatible compilers +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9) +#undef YAML_CONFIGURATION_USE_REGEX +#endif + class YamlConfiguration : public FlowConfiguration { public: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a507e3cc/libminifi/src/core/yaml/YamlConfiguration.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/yaml/YamlConfiguration.cpp b/libminifi/src/core/yaml/YamlConfiguration.cpp index a41b449..f7bd4ba 100644 --- a/libminifi/src/core/yaml/YamlConfiguration.cpp +++ b/libminifi/src/core/yaml/YamlConfiguration.cpp @@ -22,6 +22,10 @@ #include "core/yaml/YamlConfiguration.h" +#ifdef YAML_CONFIGURATION_USE_REGEX +#include <regex> +#endif // YAML_CONFIGURATION_USE_REGEX + namespace org { namespace apache { namespace nifi { @@ -806,6 +810,10 @@ void YamlConfiguration::validateComponentProperties(const std::shared_ptr<Config for (const auto &prop_pair : component_properties) { const auto &dep_props = prop_pair.second.getDependentProperties(); + if (prop_pair.second.getValue().empty()) { + continue; + } + for (const auto &dep_prop_key : dep_props) { if (component_properties.at(dep_prop_key).getValue().empty()) { std::string reason("property '"); @@ -817,6 +825,33 @@ void YamlConfiguration::validateComponentProperties(const std::shared_ptr<Config } } } + +#ifdef YAML_CONFIGURATION_USE_REGEX + // Validate mutually-exclusive properties + for (const auto &prop_pair : component_properties) { + const auto &excl_props = prop_pair.second.getExclusiveOfProperties(); + + if (prop_pair.second.getValue().empty()) { + continue; + } + + for (const auto &excl_pair : excl_props) { + std::regex excl_expr(excl_pair.second); + if (std::regex_match(component_properties.at(excl_pair.first).getValue(), excl_expr)) { + std::string reason("property '"); + reason.append(prop_pair.second.getName()); + reason.append("' is exclusive of property '"); + reason.append(excl_pair.first); + reason.append("' values matching '"); + reason.append(excl_pair.second); + reason.append("'"); + raiseComponentError(component_name, yaml_section, reason); + } + } + } +#else + logging::LOG_INFO(logger_) << "Validation of mutally-exclusive properties is disabled in this build."; +#endif // YAML_CONFIGURATION_USE_REGEX } void YamlConfiguration::raiseComponentError(const std::string &component_name, http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a507e3cc/libminifi/test/unit/YamlConfigurationTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/unit/YamlConfigurationTests.cpp b/libminifi/test/unit/YamlConfigurationTests.cpp index 61fe7f1..6cd67ac 100644 --- a/libminifi/test/unit/YamlConfigurationTests.cpp +++ b/libminifi/test/unit/YamlConfigurationTests.cpp @@ -517,3 +517,59 @@ TEST_CASE("Test Dependent Property 2", "[YamlConfigurationDependentProperty2]") } REQUIRE(config_failed); } + +#ifdef YAML_CONFIGURATION_USE_REGEX +TEST_CASE("Test Exclusive Property", "[YamlConfigurationExclusiveProperty]") { + TestController test_controller; + + LogTestController &logTestController = LogTestController::getInstance(); + logTestController.setDebug<TestPlan>(); + logTestController.setDebug<core::YamlConfiguration>(); + + std::shared_ptr<core::Repository> testProvRepo = core::createRepository("provenancerepository", true); + std::shared_ptr<core::Repository> testFlowFileRepo = core::createRepository("flowfilerepository", true); + std::shared_ptr<minifi::Configure> configuration = std::make_shared<minifi::Configure>(); + std::shared_ptr<minifi::io::StreamFactory> streamFactory = minifi::io::StreamFactory::getInstance(configuration); + std::shared_ptr<core::ContentRepository> + content_repo = std::make_shared<core::repository::VolatileContentRepository>(); + core::YamlConfiguration yamlConfig(testProvRepo, testFlowFileRepo, content_repo, streamFactory, configuration); + const auto component = std::make_shared<DummyComponent>(); + std::set<core::Property> props; + props.emplace(core::Property("Prop A", "Prop A desc", "val A", true, {}, {})); + props.emplace(core::Property("Prop B", "Prop B desc", "val B", true, {}, {{"Prop A", "^abcd.*$"}})); + component->setSupportedProperties(std::move(props)); + yamlConfig.validateComponentProperties(component, "component A", "section A"); + REQUIRE(true); // Expected to get here w/o any exceptions +} + +TEST_CASE("Test Exclusive Property 2", "[YamlConfigurationExclusiveProperty2]") { + TestController test_controller; + + LogTestController &logTestController = LogTestController::getInstance(); + logTestController.setDebug<TestPlan>(); + logTestController.setDebug<core::YamlConfiguration>(); + + std::shared_ptr<core::Repository> testProvRepo = core::createRepository("provenancerepository", true); + std::shared_ptr<core::Repository> testFlowFileRepo = core::createRepository("flowfilerepository", true); + std::shared_ptr<minifi::Configure> configuration = std::make_shared<minifi::Configure>(); + std::shared_ptr<minifi::io::StreamFactory> streamFactory = minifi::io::StreamFactory::getInstance(configuration); + std::shared_ptr<core::ContentRepository> + content_repo = std::make_shared<core::repository::VolatileContentRepository>(); + core::YamlConfiguration yamlConfig(testProvRepo, testFlowFileRepo, content_repo, streamFactory, configuration); + const auto component = std::make_shared<DummyComponent>(); + std::set<core::Property> props; + props.emplace(core::Property("Prop A", "Prop A desc", "val A", true, {}, {})); + props.emplace(core::Property("Prop B", "Prop B desc", "val B", true, {}, {{"Prop A", "^val.*$"}})); + component->setSupportedProperties(std::move(props)); + bool config_failed = false; + try { + yamlConfig.validateComponentProperties(component, "component A", "section A"); + } catch (const std::exception &e) { + config_failed = true; + REQUIRE("Unable to parse configuration file for component named 'component A' because " + "property 'Prop B' is exclusive of property 'Prop A' values matching '^val.*$' " + "[in 'section A' section of configuration file]" == std::string(e.what())); + } + REQUIRE(config_failed); +} +#endif // YAML_CONFIGURATION_USE_REGEX
