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());