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

Reply via email to