This is an automated email from the ASF dual-hosted git repository.

phrocker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


The following commit(s) were added to refs/heads/master by this push:
     new 102df8d  MINIFICPP-842 - CivetWeb tests should use random port
102df8d is described below

commit 102df8d3f61fe5e91573da378855d54111b97196
Author: Arpad Boda <[email protected]>
AuthorDate: Wed May 15 12:27:50 2019 +0200

    MINIFICPP-842 - CivetWeb tests should use random port
    
    This closes #554.
    
    Signed-off-by: Marc Parisi <[email protected]>
---
 extensions/civetweb/processors/ListenHTTP.cpp   | 51 ++++++++++++++++++++-----
 extensions/civetweb/processors/ListenHTTP.h     |  3 ++
 libminifi/include/core/PropertyValidation.h     | 16 ++++++++
 libminifi/test/civetweb-tests/CivetwebTests.cpp | 13 ++++---
 4 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/extensions/civetweb/processors/ListenHTTP.cpp 
b/extensions/civetweb/processors/ListenHTTP.cpp
index dbb00a4..a6c2ef7 100644
--- a/extensions/civetweb/processors/ListenHTTP.cpp
+++ b/extensions/civetweb/processors/ListenHTTP.cpp
@@ -27,11 +27,16 @@ namespace minifi {
 namespace processors {
 
 core::Property ListenHTTP::BasePath(
-    core::PropertyBuilder::createProperty("Base Path")->withDescription("Base 
path for incoming 
connections")->isRequired(false)->withDefaultValue<std::string>("contentListener")->build());
+    core::PropertyBuilder::createProperty("Base Path")
+        ->withDescription("Base path for incoming connections")
+        ->isRequired(false)
+        ->withDefaultValue<std::string>("contentListener")->build());
 
 core::Property ListenHTTP::Port(
-    core::PropertyBuilder::createProperty("Listening 
Port")->withDescription("The Port to listen on for incoming 
connections")->isRequired(true)->withDefaultValue<int>(
-        80, core::StandardValidators::PORT_VALIDATOR())->build());
+    core::PropertyBuilder::createProperty("Listening Port")
+        ->withDescription("The Port to listen on for incoming connections. 0 
means port is going to be selected randomly.")
+        ->isRequired(true)
+        ->withDefaultValue<int>(80, 
core::StandardValidators::LISTEN_PORT_VALIDATOR())->build());
 
 core::Property ListenHTTP::AuthorizedDNPattern("Authorized DN Pattern", "A 
Regular Expression to apply against the Distinguished Name of incoming"
                                                " connections. If the Pattern 
does not match the DN, the connection will be refused.",
@@ -40,12 +45,18 @@ core::Property ListenHTTP::SSLCertificate("SSL 
Certificate", "File containing PE
 core::Property ListenHTTP::SSLCertificateAuthority("SSL Certificate 
Authority", "File containing trusted PEM-formatted certificates", "");
 
 core::Property ListenHTTP::SSLVerifyPeer(
-    core::PropertyBuilder::createProperty("SSL Verify 
Peer")->withDescription("Whether or not to verify the client's certificate 
(yes/no)")->isRequired(false)->withAllowableValue<std::string>("yes")
-        ->withAllowableValue("no")->withDefaultValue("no")->build());
+    core::PropertyBuilder::createProperty("SSL Verify Peer")
+        ->withDescription("Whether or not to verify the client's certificate 
(yes/no)")
+        ->isRequired(false)
+        ->withAllowableValues<std::string>({"yes", "no"})
+        ->withDefaultValue("no")->build());
 
 core::Property ListenHTTP::SSLMinimumVersion(
-    core::PropertyBuilder::createProperty("SSL Minimum 
Version")->withDescription("Minimum TLS/SSL version allowed (SSL2, SSL3, 
TLS1.0, TLS1.1, TLS1.2)")->isRequired(false)
-        
->withAllowableValue<std::string>("SSL2")->withAllowableValue("SSL3")->withAllowableValue("TLS1.0")->withAllowableValue("TLS1.1")->withAllowableValue("TLS1.2")->withDefaultValue("SSL2")->build());
+    core::PropertyBuilder::createProperty("SSL Minimum Version")
+        -> withDescription("Minimum TLS/SSL version allowed (SSL2, SSL3, 
TLS1.0, TLS1.1, TLS1.2)")
+        ->isRequired(false)
+        ->withAllowableValues<std::string>({"SSL2", "SSL3", "TLS1.0", 
"TLS1.1", "TLS1.2"})
+        ->withDefaultValue("SSL2")->build());
 
 core::Property ListenHTTP::HeadersAsAttributesRegex("HTTP Headers to receive 
as Attributes (Regex)", "Specifies the Regular Expression that determines the 
names of HTTP Headers that"
                                                     " should be passed along 
as FlowFile attributes",
@@ -83,13 +94,14 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, 
core::ProcessSessionF
 
   basePath.insert(0, "/");
 
-  std::string listeningPort;
 
   if (!context->getProperty(Port.getName(), listeningPort)) {
     logger_->log_error("%s attribute is missing or invalid", Port.getName());
     return;
   }
 
+  bool randomPort = listeningPort == "0";
+
   std::string authDNPattern;
 
   if (context->getProperty(AuthorizedDNPattern.getName(), authDNPattern) && 
!authDNPattern.empty()) {
@@ -135,7 +147,7 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, 
core::ProcessSessionF
 
   auto numThreads = getMaxConcurrentTasks();
 
-  logger_->log_info("ListenHTTP starting HTTP server on port %s and path %s 
with %d threads", listeningPort, basePath, numThreads);
+  logger_->log_info("ListenHTTP starting HTTP server on port %s and path %s 
with %d threads", randomPort ? "random" : listeningPort, basePath, numThreads);
 
   // Initialize web server
   std::vector<std::string> options;
@@ -191,6 +203,16 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, 
core::ProcessSessionF
   server_.reset(new CivetServer(options));
   handler_.reset(new Handler(basePath, context, sessionFactory, 
std::move(authDNPattern), std::move(headersAsAttributesPattern)));
   server_->addHandler(basePath, handler_.get());
+
+  if (randomPort) {
+    const auto& vec = server_->getListeningPorts();
+    if (vec.size() != 1) {
+      logger_->log_error("Random port is set, but there is no listening port! 
Server most probably failed to start!");
+    } else {
+      listeningPort = std::to_string(vec[0]);
+      logger_->log_info("Listening on port %s", listeningPort);
+    }
+  }
 }
 
 ListenHTTP::~ListenHTTP() {
@@ -441,6 +463,17 @@ int64_t 
ListenHTTP::WriteCallback::process(std::shared_ptr<io::BaseStream> strea
   return nlen;
 }
 
+bool ListenHTTP::isSecure() const {
+  return (listeningPort.length() > 0) && *listeningPort.rbegin() == 's';
+}
+
+std::string ListenHTTP::getPort() const {
+  if(isSecure()) {
+    return listeningPort.substr(0, listeningPort.length() -1);
+  }
+  return listeningPort;
+}
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/civetweb/processors/ListenHTTP.h 
b/extensions/civetweb/processors/ListenHTTP.h
index bce0b9e..f337c7d 100644
--- a/extensions/civetweb/processors/ListenHTTP.h
+++ b/extensions/civetweb/processors/ListenHTTP.h
@@ -70,6 +70,8 @@ class ListenHTTP : public core::Processor {
   void onTrigger(core::ProcessContext *context, core::ProcessSession *session);
   void initialize();
   void onSchedule(core::ProcessContext *context, core::ProcessSessionFactory 
*sessionFactory);
+  std::string getPort() const;
+  bool isSecure() const;
 
   struct response_body {
     std::string uri;
@@ -167,6 +169,7 @@ class ListenHTTP : public core::Processor {
 
   std::unique_ptr<CivetServer> server_;
   std::unique_ptr<Handler> handler_;
+  std::string listeningPort;
 };
 
 REGISTER_RESOURCE(ListenHTTP, "Starts an HTTP Server and listens on a given 
base path to transform incoming requests into FlowFiles. The default URI of the 
Service will be "
diff --git a/libminifi/include/core/PropertyValidation.h 
b/libminifi/include/core/PropertyValidation.h
index 2938300..2df5218 100644
--- a/libminifi/include/core/PropertyValidation.h
+++ b/libminifi/include/core/PropertyValidation.h
@@ -275,6 +275,17 @@ class PortValidator : public LongValidator {
   }
 };
 
+//Use only for specifying listen ports, where 0 means a randomly chosen one!
+class ListenPortValidator : public LongValidator {
+public:
+  ListenPortValidator(const std::string &name)
+    : LongValidator(name, 0, 65535) {
+  }
+  virtual ~ListenPortValidator() {
+
+  }
+};
+
 class TimePeriodValidator : public PropertyValidator {
  public:
   TimePeriodValidator(const std::string &name)
@@ -330,6 +341,11 @@ class StandardValidators {
     return validator;
   }
 
+  static const std::shared_ptr<PropertyValidator> LISTEN_PORT_VALIDATOR(){
+    static std::shared_ptr<PropertyValidator> validator = 
std::make_shared<ListenPortValidator>("LISTEN_PORT_VALIDATOR");
+    return validator;
+  }
+
  private:
   std::shared_ptr<PropertyValidator> INVALID;
   std::shared_ptr<PropertyValidator> INTEGER_VALIDATOR;
diff --git a/libminifi/test/civetweb-tests/CivetwebTests.cpp 
b/libminifi/test/civetweb-tests/CivetwebTests.cpp
index 7018150..516022d 100644
--- a/libminifi/test/civetweb-tests/CivetwebTests.cpp
+++ b/libminifi/test/civetweb-tests/CivetwebTests.cpp
@@ -93,10 +93,7 @@ TEST_CASE("Test GET Body", "[ListenHTTPGETBody]") {  // 
NOLINT
       "ListenHTTP",
       core::Relationship("success", "description"),
       true);
-  plan->setProperty(
-      listen,
-      "Listening Port",
-      "8888");
+  plan->setProperty(listen, "Listening Port", "0");
   listen->setAutoTerminatedRelationships({{"success", ""}});
 
   plan->runNextProcessor();  // Get
@@ -104,8 +101,12 @@ TEST_CASE("Test GET Body", "[ListenHTTPGETBody]") {  // 
NOLINT
   plan->runNextProcessor();  // Log
   plan->runNextProcessor();  // Listen
 
-  sleep(1);
-  utils::HTTPClient client("http://localhost:8888/contentListener/test";);
+  auto raw_ptr = 
dynamic_cast<org::apache::nifi::minifi::processors::ListenHTTP*>(listen.get());
+  std::string protocol = std::string("http") + (raw_ptr->isSecure() ? "s" : 
"");
+  std::string portstr = raw_ptr->getPort();
+  REQUIRE(LogTestController::getInstance().contains("Listening on port " + 
portstr));
+
+  utils::HTTPClient client(protocol + "://localhost:" + portstr + 
"/contentListener/test");
   REQUIRE(client.submit());
   const auto &body_chars = client.getResponseBody();
   std::string response_body(body_chars.data(), body_chars.size());

Reply via email to