Repository: nifi-minifi-cpp
Updated Branches:
  refs/heads/master 906afb179 -> 54be9d403


MINIFICPP-501 Incorporate dependent property metadata into agent information

MINIFICPP-502 Add validation to config parser to validate required properties

This closes #334, closes #333.

Signed-off-by: Marc Parisi <[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/54be9d40
Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/tree/54be9d40
Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/diff/54be9d40

Branch: refs/heads/master
Commit: 54be9d403a0e588d27ebda9ea0b90ec558f970cb
Parents: 906afb1
Author: Andrew I. Christianson <[email protected]>
Authored: Mon May 21 11:55:14 2018 -0400
Committer: Marc Parisi <[email protected]>
Committed: Thu May 24 13:38:01 2018 -0400

----------------------------------------------------------------------
 libminifi/include/core/Property.h               |  9 ++-
 .../include/core/state/nodes/AgentInformation.h | 10 +++
 libminifi/include/core/yaml/YamlConfiguration.h |  5 +-
 libminifi/src/core/ConfigurableComponent.cpp    |  2 +-
 libminifi/src/core/Property.cpp                 |  6 ++
 libminifi/src/core/yaml/YamlConfiguration.cpp   | 72 ++++++++++++-----
 libminifi/src/processors/GetFile.cpp            |  2 +-
 libminifi/src/processors/PutFile.cpp            |  4 +-
 .../unit/PropertyValidationAgentInfoTests.cpp   | 27 ++++++-
 libminifi/test/unit/YamlConfigurationTests.cpp  | 81 ++++++++++++++++++++
 10 files changed, 191 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/include/core/Property.h
----------------------------------------------------------------------
diff --git a/libminifi/include/core/Property.h 
b/libminifi/include/core/Property.h
index 9aa19e5..9fb31fb 100644
--- a/libminifi/include/core/Property.h
+++ b/libminifi/include/core/Property.h
@@ -56,10 +56,15 @@ class Property {
   /*!
    * Create a new property
    */
-  Property(const std::string name, const std::string description, const 
std::string value, bool is_required)
+  Property(const std::string name,
+           const std::string description,
+           const std::string value,
+           bool is_required,
+           std::vector<std::string> &&dependent_properties)
       : name_(name),
         description_(description),
         is_required_(is_required),
+        dependent_properties_(std::move(dependent_properties)),
         is_collection_(false) {
     values_.push_back(std::string(value.c_str()));
   }
@@ -95,6 +100,7 @@ class Property {
   std::string getDescription() const;
   std::string getValue() const;
   bool getRequired() const;
+  std::vector<std::string> getDependentProperties() const;
   std::vector<std::string> &getValues();
 
   // Set value for the property
@@ -372,6 +378,7 @@ class Property {
   std::string name_;
   std::string description_;
   bool is_required_;
+  std::vector<std::string> dependent_properties_;
   bool is_collection_;
   std::vector<std::string> values_;
 

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/include/core/state/nodes/AgentInformation.h
----------------------------------------------------------------------
diff --git a/libminifi/include/core/state/nodes/AgentInformation.h 
b/libminifi/include/core/state/nodes/AgentInformation.h
index c406610..b5b5df6 100644
--- a/libminifi/include/core/state/nodes/AgentInformation.h
+++ b/libminifi/include/core/state/nodes/AgentInformation.h
@@ -297,9 +297,19 @@ class ComponentManifest : public DeviceInformation {
             descriptorRequired.name = "required";
             descriptorRequired.value = prop.second.getRequired();
 
+            SerializedResponseNode descriptorDependentProperties;
+            descriptorDependentProperties.name = "dependentProperties";
+
+            for (const auto &propName : prop.second.getDependentProperties()) {
+              SerializedResponseNode descriptorDependentProperty;
+              descriptorDependentProperty.name = propName;
+              
descriptorDependentProperties.children.push_back(descriptorDependentProperty);
+            }
+
             child.children.push_back(descriptorName);
             child.children.push_back(descriptorDescription);
             child.children.push_back(descriptorRequired);
+            child.children.push_back(descriptorDependentProperties);
 
             props.children.push_back(child);
           }

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/include/core/yaml/YamlConfiguration.h
----------------------------------------------------------------------
diff --git a/libminifi/include/core/yaml/YamlConfiguration.h 
b/libminifi/include/core/yaml/YamlConfiguration.h
index da71ba6..1d0a332 100644
--- a/libminifi/include/core/yaml/YamlConfiguration.h
+++ b/libminifi/include/core/yaml/YamlConfiguration.h
@@ -241,7 +241,10 @@ class YamlConfiguration : public FlowConfiguration {
    * @param propertiesNode the YAML::Node containing the properties
    * @param processor      the Processor to which to add the resulting 
properties
    */
-  void parsePropertiesNodeYaml(YAML::Node *propertiesNode, 
std::shared_ptr<core::ConfigurableComponent> processor);
+  void parsePropertiesNodeYaml(YAML::Node *propertiesNode,
+                               std::shared_ptr<core::ConfigurableComponent> 
processor,
+                               const std::string &component_name,
+                               const std::string &yaml_section);
 
   /**
    * A helper function for parsing or generating optional id fields.

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/src/core/ConfigurableComponent.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/core/ConfigurableComponent.cpp 
b/libminifi/src/core/ConfigurableComponent.cpp
index b81c20d..2b89acc 100644
--- a/libminifi/src/core/ConfigurableComponent.cpp
+++ b/libminifi/src/core/ConfigurableComponent.cpp
@@ -190,7 +190,7 @@ bool ConfigurableComponent::createDynamicProperty(const 
std::string &name, const
     return false;
   }
 
-  Property new_property(name, DEFAULT_DYNAMIC_PROPERTY_DESC, value, false);
+  Property new_property(name, DEFAULT_DYNAMIC_PROPERTY_DESC, value, false, {});
   logger_->log_info("Processor %s dynamic property '%s' value '%s'", 
name.c_str(), new_property.getName().c_str(), value.c_str());
   dynamic_properties_[new_property.getName()] = new_property;
   onDynamicPropertyModified({}, new_property);

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/src/core/Property.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/core/Property.cpp b/libminifi/src/core/Property.cpp
index ebfcf0c..635dca5 100644
--- a/libminifi/src/core/Property.cpp
+++ b/libminifi/src/core/Property.cpp
@@ -71,9 +71,15 @@ const Property &Property::operator=(const Property &other) {
   values_ = other.values_;
   description_ = other.description_;
   is_collection_ = other.is_collection_;
+  is_required_ = other.is_required_;
+  dependent_properties_ = other.dependent_properties_;
   return *this;
 }
 
+std::vector<std::string> Property::getDependentProperties() const {
+  return dependent_properties_;
+}
+
 } /* namespace core */
 } /* namespace minifi */
 } /* namespace nifi */

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/src/core/yaml/YamlConfiguration.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/core/yaml/YamlConfiguration.cpp 
b/libminifi/src/core/yaml/YamlConfiguration.cpp
index fbe84ed..54c5e07 100644
--- a/libminifi/src/core/yaml/YamlConfiguration.cpp
+++ b/libminifi/src/core/yaml/YamlConfiguration.cpp
@@ -17,7 +17,6 @@
  */
 
 #include <memory>
-#include <string>
 #include <vector>
 #include <set>
 
@@ -172,7 +171,7 @@ void YamlConfiguration::parseProcessorNodeYaml(YAML::Node 
processorsNode, core::
         // handle processor properties
         if (procNode["Properties"]) {
           YAML::Node propertiesNode = procNode["Properties"];
-          parsePropertiesNodeYaml(&propertiesNode, processor);
+          parsePropertiesNodeYaml(&propertiesNode, processor, procCfg.name, 
CONFIG_YAML_PROCESSORS_KEY);
         }
 
         // Take care of scheduling
@@ -237,7 +236,7 @@ void YamlConfiguration::parseProcessorNodeYaml(YAML::Node 
processorsNode, core::
     }
   } else {
     throw new std::invalid_argument("Cannot instantiate a MiNiFi instance 
without a defined "
-                                        "Processors configuration node.");
+                                    "Processors configuration node.");
   }
 }
 
@@ -468,12 +467,16 @@ void 
YamlConfiguration::parseControllerServices(YAML::Node *controllerServicesNo
             logger_->log_debug("Created Controller Service with UUID %s and 
name %s", id, name);
             controller_service_node->initialize();
             YAML::Node propertiesNode = controllerServiceNode["Properties"];
-            // we should propogate propertiets to the node and to the 
implementation
+            // we should propogate properties to the node and to the 
implementation
             parsePropertiesNodeYaml(&propertiesNode,
-                                    
std::static_pointer_cast<core::ConfigurableComponent>(controller_service_node));
+                                    
std::static_pointer_cast<core::ConfigurableComponent>(controller_service_node),
+                                    name,
+                                    CONFIG_YAML_CONTROLLER_SERVICES_KEY);
             if (controller_service_node->getControllerServiceImplementation() 
!= nullptr) {
               parsePropertiesNodeYaml(&propertiesNode,
-                                      
std::static_pointer_cast<core::ConfigurableComponent>(controller_service_node->getControllerServiceImplementation()));
+                                      
std::static_pointer_cast<core::ConfigurableComponent>(controller_service_node->getControllerServiceImplementation()),
+                                      name,
+                                      CONFIG_YAML_CONTROLLER_SERVICES_KEY);
             }
           }
           controller_services_->put(id, controller_service_node);
@@ -563,7 +566,7 @@ void YamlConfiguration::parseConnectionYaml(YAML::Node 
*connectionsNode, core::P
           std::string connectionSrcProcId = connectionNode["source 
id"].as<std::string>();
           uuid_parse(connectionSrcProcId.c_str(), srcUUID);
           logger_->log_debug("Using 'source id' to match source with same id 
for "
-                                 "connection '%s': source id => [%s]",
+                             "connection '%s': source id => [%s]",
                              name, connectionSrcProcId);
         } else {
           // if we don't have a source id, try to resolve using source name. 
config schema v2 will make this unnecessary
@@ -575,7 +578,7 @@ void YamlConfiguration::parseConnectionYaml(YAML::Node 
*connectionsNode, core::P
             // the source name is a remote port id, so use that as the source 
id
             uuid_copy(srcUUID, tmpUUID);
             logger_->log_debug("Using 'source name' containing a remote port 
id to match the source for "
-                                   "connection '%s': source name => [%s]",
+                               "connection '%s': source name => [%s]",
                                name, connectionSrcProcName);
           } else {
             // lastly, look the processor up by name
@@ -583,7 +586,7 @@ void YamlConfiguration::parseConnectionYaml(YAML::Node 
*connectionsNode, core::P
             if (NULL != srcProcessor) {
               srcProcessor->getUUID(srcUUID);
               logger_->log_debug("Using 'source name' to match source with 
same name for "
-                                     "connection '%s': source name => [%s]",
+                                 "connection '%s': source name => [%s]",
                                  name, connectionSrcProcName);
             } else {
               // we ran out of ways to discover the source processor
@@ -602,7 +605,7 @@ void YamlConfiguration::parseConnectionYaml(YAML::Node 
*connectionsNode, core::P
           std::string connectionDestProcId = connectionNode["destination 
id"].as<std::string>();
           uuid_parse(connectionDestProcId.c_str(), destUUID);
           logger_->log_debug("Using 'destination id' to match destination with 
same id for "
-                                 "connection '%s': destination id => [%s]",
+                             "connection '%s': destination id => [%s]",
                              name, connectionDestProcId);
         } else {
           // we use the same logic as above for resolving the source processor
@@ -616,7 +619,7 @@ void YamlConfiguration::parseConnectionYaml(YAML::Node 
*connectionsNode, core::P
             // the destination name is a remote port id, so use that as the 
dest id
             uuid_copy(destUUID, tmpUUID);
             logger_->log_debug("Using 'destination name' containing a remote 
port id to match the destination for "
-                                   "connection '%s': destination name => [%s]",
+                               "connection '%s': destination name => [%s]",
                                name, connectionDestProcName);
           } else {
             // look the processor up by name
@@ -624,7 +627,7 @@ void YamlConfiguration::parseConnectionYaml(YAML::Node 
*connectionsNode, core::P
             if (NULL != destProcessor) {
               destProcessor->getUUID(destUUID);
               logger_->log_debug("Using 'destination name' to match 
destination with same name for "
-                                     "connection '%s': destination name => 
[%s]",
+                                 "connection '%s': destination name => [%s]",
                                  name, connectionDestProcName);
             } else {
               // we ran out of ways to discover the destination processor
@@ -666,10 +669,10 @@ void YamlConfiguration::parsePortYaml(YAML::Node 
*portNode,
   checkRequiredField(&inputPortsObj, "id",
                      CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY,
                      "The field 'id' is required for "
-                         "the port named '" + nameStr + "' in the YAML Config. 
If this port "
-                         "is an input port for a NiFi Remote Process Group, 
the port "
-                         "id should match the corresponding id specified in 
the NiFi configuration. "
-                         "This is a UUID of the format 
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.");
+                     "the port named '" + nameStr + "' in the YAML Config. If 
this port "
+                                                    "is an input port for a 
NiFi Remote Process Group, the port "
+                                                    "id should match the 
corresponding id specified in the NiFi configuration. "
+                                                    "This is a UUID of the 
format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.");
   auto portId = inputPortsObj["id"].as<std::string>();
   uuid_parse(portId.c_str(), uuid);
 
@@ -696,7 +699,10 @@ void YamlConfiguration::parsePortYaml(YAML::Node *portNode,
   // handle port properties
   YAML::Node nodeVal = portNode->as<YAML::Node>();
   YAML::Node propertiesNode = nodeVal["Properties"];
-  parsePropertiesNodeYaml(&propertiesNode, 
std::static_pointer_cast<core::ConfigurableComponent>(processor));
+  parsePropertiesNodeYaml(&propertiesNode,
+                          
std::static_pointer_cast<core::ConfigurableComponent>(processor),
+                          nameStr,
+                          CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
 
   // add processor to parent
   parent->addProcessor(processor);
@@ -714,7 +720,9 @@ void YamlConfiguration::parsePortYaml(YAML::Node *portNode,
 }
 
 void YamlConfiguration::parsePropertiesNodeYaml(YAML::Node *propertiesNode,
-                                                
std::shared_ptr<core::ConfigurableComponent> processor) {
+                                                
std::shared_ptr<core::ConfigurableComponent> processor,
+                                                const std::string 
&component_name,
+                                                const std::string 
&yaml_section) {
   // Treat generically as a YAML node so we can perform inspection on entries 
to ensure they are populated
   for (YAML::const_iterator propsIter = propertiesNode->begin(); propsIter != 
propertiesNode->end(); ++propsIter) {
     std::string propertyName = propsIter->first.as<std::string>();
@@ -732,7 +740,7 @@ void YamlConfiguration::parsePropertiesNodeYaml(YAML::Node 
*propertiesNode,
               std::shared_ptr<core::Connectable> proc = 
std::dynamic_pointer_cast<core::Connectable>(processor);
               if (proc != 0) {
                 logger_->log_warn("Received property %s with value %s but is 
not one of the properties for %s. "
-                                      "Attempting to add as dynamic property.",
+                                  "Attempting to add as dynamic property.",
                                   propertyName,
                                   rawValueString,
                                   proc->getName());
@@ -755,7 +763,7 @@ void YamlConfiguration::parsePropertiesNodeYaml(YAML::Node 
*propertiesNode,
           std::shared_ptr<core::Connectable> proc = 
std::dynamic_pointer_cast<core::Connectable>(processor);
           if (proc != 0) {
             logger_->log_warn("Received property %s with value %s but is not 
one of the properties for %s. "
-                                  "Attempting to add as dynamic property.",
+                              "Attempting to add as dynamic property.",
                               propertyName,
                               rawValueString,
                               proc->getName());
@@ -773,6 +781,28 @@ void YamlConfiguration::parsePropertiesNodeYaml(YAML::Node 
*propertiesNode,
       }
     }
   }
+
+  // Validate required properties
+  for (const auto &prop_pair : processor->getProperties()) {
+    if (prop_pair.second.getRequired()) {
+      const auto &val = prop_pair.second.getValue();
+
+      if (val.empty()) {
+        // Build a helpful error message for the user so they can fix the
+        // invalid YAML config file, using the component name if present
+        std::string err_msg =
+            "Unable to parse configuration file for component named '"
+                + component_name
+                + "' because required property '" + prop_pair.second.getName() 
+ "' is not set";
+        if (!yaml_section.empty()) {
+          err_msg += " [in '" + yaml_section + "' section of configuration 
file]";
+        }
+        logging::LOG_ERROR(logger_) << err_msg;
+
+        throw std::invalid_argument(err_msg);
+      }
+    }
+  }
 }
 
 std::string YamlConfiguration::getOrGenerateId(YAML::Node *yamlNode, const 
std::string &idField) {
@@ -784,7 +814,7 @@ std::string YamlConfiguration::getOrGenerateId(YAML::Node 
*yamlNode, const std::
       id = node[idField].as<std::string>();
     } else {
       throw std::invalid_argument("getOrGenerateId: idField is expected to 
reference YAML::Node "
-                                      "of YAML::NodeType::Scalar.");
+                                  "of YAML::NodeType::Scalar.");
     }
   } else {
     uuid_t uuid;

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/src/processors/GetFile.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/processors/GetFile.cpp 
b/libminifi/src/processors/GetFile.cpp
index 22a2b73..63b722e 100644
--- a/libminifi/src/processors/GetFile.cpp
+++ b/libminifi/src/processors/GetFile.cpp
@@ -45,7 +45,7 @@ namespace minifi {
 namespace processors {
 
 core::Property GetFile::BatchSize("Batch Size", "The maximum number of files 
to pull in each iteration", "10");
-core::Property GetFile::Directory("Input Directory", "The input directory from 
which to pull files", ".");
+core::Property GetFile::Directory("Input Directory", "The input directory from 
which to pull files", ".", true, {});
 core::Property GetFile::IgnoreHiddenFile("Ignore Hidden Files", "Indicates 
whether or not hidden files should be ignored", "true");
 core::Property GetFile::KeepSourceFile("Keep Source File", "If true, the file 
is not deleted after it has been copied to the Content Repository", "false");
 core::Property GetFile::MaxAge("Maximum File Age", "The minimum age that a 
file must be in order to be pulled;"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/src/processors/PutFile.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/processors/PutFile.cpp 
b/libminifi/src/processors/PutFile.cpp
index f073025..99bf998 100644
--- a/libminifi/src/processors/PutFile.cpp
+++ b/libminifi/src/processors/PutFile.cpp
@@ -51,7 +51,9 @@ core::Property PutFile::CreateDirs(
     "Create Missing Directories",
     "If true, then missing destination directories will be created. "
         "If false, flowfiles are penalized and sent to failure.",
-    "true");
+    "true",
+    true,
+    {"Directory"});
 core::Property PutFile::MaxDestFiles(
     "Maximum File Count",
     "Specifies the maximum number of files that can exist in the output 
directory",

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/test/unit/PropertyValidationAgentInfoTests.cpp
----------------------------------------------------------------------
diff --git a/libminifi/test/unit/PropertyValidationAgentInfoTests.cpp 
b/libminifi/test/unit/PropertyValidationAgentInfoTests.cpp
index 149e4e9..a7b297d 100644
--- a/libminifi/test/unit/PropertyValidationAgentInfoTests.cpp
+++ b/libminifi/test/unit/PropertyValidationAgentInfoTests.cpp
@@ -25,7 +25,7 @@
 #include "core/Processor.h"
 #include "core/ClassLoader.h"
 
-TEST_CASE("TestRequired", "[required]") {
+TEST_CASE("Test Required", "[required]") {
   minifi::state::response::ComponentManifest manifest("PutFile");
   auto serialized = manifest.serialize();
   REQUIRE(serialized.size() > 0);
@@ -43,3 +43,28 @@ TEST_CASE("TestRequired", "[required]") {
   REQUIRE("required" == prop_0_required.name);
   
REQUIRE(!std::dynamic_pointer_cast<minifi::state::response::BoolValue>(prop_0_required.value.getValue())->getValue());
 }
+
+TEST_CASE("Test Dependent", "[dependent]") {
+  minifi::state::response::ComponentManifest manifest("manifest");
+  auto serialized = manifest.serialize();
+  REQUIRE(serialized.size() > 0);
+  const auto &resp = serialized[0];
+  REQUIRE(resp.children.size() > 0);
+  const auto &processors = resp.children[0];
+  REQUIRE(processors.children.size() > 0);
+  minifi::state::response::SerializedResponseNode proc_0;
+  for (const auto &node : processors.children) {
+    if ("org::apache::nifi::minifi::processors::PutFile" == node.name) {
+      proc_0 = node;
+    }
+  }
+  REQUIRE(proc_0.children.size() > 0);
+  const auto &prop_descriptors = proc_0.children[0];
+  REQUIRE(prop_descriptors.children.size() > 0);
+  const auto &prop_0 = prop_descriptors.children[1];
+  REQUIRE(prop_0.children.size() >= 3);
+  const auto &prop_0_dependent = prop_0.children[3];
+  REQUIRE("dependentProperties" == prop_0_dependent.name);
+  const auto &prop_0_dependent_0 = prop_0_dependent.children[0];
+  REQUIRE("Directory" == prop_0_dependent_0.name);
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/54be9d40/libminifi/test/unit/YamlConfigurationTests.cpp
----------------------------------------------------------------------
diff --git a/libminifi/test/unit/YamlConfigurationTests.cpp 
b/libminifi/test/unit/YamlConfigurationTests.cpp
index 0b853a6..724fc64 100644
--- a/libminifi/test/unit/YamlConfigurationTests.cpp
+++ b/libminifi/test/unit/YamlConfigurationTests.cpp
@@ -376,3 +376,84 @@ Processors:
   REQUIRE(LogTestController::getInstance().contains("[warning] Unable to set 
the dynamic property "
                                                         "Dynamic Property with 
value Bad"));
 }
+
+
+TEST_CASE("Test Required Property", "[YamlConfigurationRequiredProperty]") {
+  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 = 
std::make_shared<minifi::io::StreamFactory>(configuration);
+  std::shared_ptr<core::ContentRepository>
+      content_repo = 
std::make_shared<core::repository::VolatileContentRepository>();
+  core::YamlConfiguration *yamlConfig =
+      new core::YamlConfiguration(testProvRepo, testFlowFileRepo, 
content_repo, streamFactory, configuration);
+
+  static const std::string TEST_CONFIG_YAML = R"(
+Flow Controller:
+  name: Simple
+Processors:
+- name: XYZ
+  class: GetFile
+  Properties:
+    Input Directory: ""
+    Batch Size: 1
+      )";
+  std::istringstream configYamlStream(TEST_CONFIG_YAML);
+  bool caught_exception = false;
+
+  try {
+    std::unique_ptr<core::ProcessGroup> rootFlowConfig = 
yamlConfig->getYamlRoot(configYamlStream);
+
+    REQUIRE(rootFlowConfig);
+    REQUIRE(rootFlowConfig->findProcessor("GetFile"));
+    REQUIRE(NULL != rootFlowConfig->findProcessor("GetFile")->getUUID());
+    REQUIRE(!rootFlowConfig->findProcessor("GetFile")->getUUIDStr().empty());
+  } catch (const std::exception &e) {
+    caught_exception = true;
+    REQUIRE("Unable to parse configuration file for component named 'XYZ' 
because required property "
+            "'Input Directory' is not set [in 'Processors' section of 
configuration file]" == std::string(e.what()));
+  }
+
+  REQUIRE(caught_exception);
+}
+
+TEST_CASE("Test Required Property 2", "[YamlConfigurationRequiredProperty2]") {
+  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 = 
std::make_shared<minifi::io::StreamFactory>(configuration);
+  std::shared_ptr<core::ContentRepository>
+      content_repo = 
std::make_shared<core::repository::VolatileContentRepository>();
+  core::YamlConfiguration *yamlConfig =
+      new core::YamlConfiguration(testProvRepo, testFlowFileRepo, 
content_repo, streamFactory, configuration);
+
+  static const std::string TEST_CONFIG_YAML = R"(
+Flow Controller:
+  name: Simple
+Processors:
+- name: XYZ
+  class: GetFile
+  Properties:
+    Input Directory: "/"
+    Batch Size: 1
+      )";
+  std::istringstream configYamlStream(TEST_CONFIG_YAML);
+  std::unique_ptr<core::ProcessGroup> rootFlowConfig = 
yamlConfig->getYamlRoot(configYamlStream);
+
+  REQUIRE(rootFlowConfig);
+  REQUIRE(rootFlowConfig->findProcessor("XYZ"));
+  REQUIRE(NULL != rootFlowConfig->findProcessor("XYZ")->getUUID());
+  REQUIRE(!rootFlowConfig->findProcessor("XYZ")->getUUIDStr().empty());
+}

Reply via email to