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

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

commit d23e59615ffb64d1e09cd95c896939a814a011cd
Author: Adam Debreceni <adebrec...@apache.org>
AuthorDate: Tue Apr 18 21:16:33 2023 +0200

    MINIFICPP-2105 - Validate ConsumeWindowsEventLogs output/json format
    
    Closes #1559
    
    Signed-off-by: Martin Zink <martinz...@apache.org>
---
 .../windows-event-log/ConsumeWindowsEventLog.cpp   | 93 ++++++++++------------
 .../windows-event-log/ConsumeWindowsEventLog.h     | 48 +++++------
 extensions/windows-event-log/tests/CWELTestUtils.h |  4 +-
 .../tests/ConsumeWindowsEventLogTests.cpp          | 17 ++--
 4 files changed, 69 insertions(+), 93 deletions(-)

diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp 
b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
index abf21def3..d37526c6c 100644
--- a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
+++ b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
@@ -51,6 +51,7 @@
 
 #include "utils/gsl.h"
 #include "utils/OsUtils.h"
+#include "utils/ProcessorConfigUtils.h"
 
 #pragma comment(lib, "wevtapi.lib")
 #pragma comment(lib, "ole32.lib")
@@ -137,19 +138,19 @@ const core::Property ConsumeWindowsEventLog::EventHeader(
       "EVENTID,TASK_CATEGORY,LEVEL,KEYWORDS,USER,COMPUTER, and EVENT_TYPE. 
Eliminating fields will remove them from the header.")->
   build());
 
-const core::Property ConsumeWindowsEventLog::OutputFormat(
+const core::Property ConsumeWindowsEventLog::OutputFormatProperty(
   core::PropertyBuilder::createProperty("Output Format")->
   isRequired(true)->
-  withDefaultValue(Both)->
-  withAllowableValues<std::string>({XML, Plaintext, Both, JSON})->
+  withDefaultValue(toString(OutputFormat::BOTH))->
+  withAllowableValues(OutputFormat::values())->
   withDescription("Set the output format type. In case \'Both\' is selected 
the processor generates two flow files for every event captured in format XML 
and Plaintext")->
   build());
 
-const core::Property ConsumeWindowsEventLog::JSONFormat(
+const core::Property ConsumeWindowsEventLog::JsonFormatProperty(
   core::PropertyBuilder::createProperty("JSON Format")->
   isRequired(true)->
-  withDefaultValue(JSONSimple)->
-  
withAllowableValue<std::string>(JSONSimple)->withAllowableValue(JSONRaw)->withAllowableValue(JSONFlattened)->
+  withDefaultValue(toString(JsonFormat::SIMPLE))->
+  withAllowableValues(JsonFormat::values())->
   withDescription("Set the json format type. Only applicable if Output Format 
is set to 'JSON'")->
   build());
 
@@ -266,34 +267,10 @@ void ConsumeWindowsEventLog::onSchedule(const 
std::shared_ptr<core::ProcessConte
     regex_.emplace(*identifier_matcher);
   }
 
-  std::string mode;
-  context->getProperty(OutputFormat.getName(), mode);
-
-  output_ = {};
-  if (mode == XML) {
-    output_.xml = true;
-  } else if (mode == Plaintext) {
-    output_.plaintext = true;
-  } else if (mode == Both) {
-    output_.xml = true;
-    output_.plaintext = true;
-  } else if (mode == JSON) {
-    std::string json_format;
-    context->getProperty(JSONFormat.getName(), json_format);
-    if (json_format == JSONRaw) {
-      output_.json.type = JSONType::Raw;
-    } else if (json_format == JSONSimple) {
-      output_.json.type = JSONType::Simple;
-    } else if (json_format == JSONFlattened) {
-      output_.json.type = JSONType::Flattened;
-    }
-  } else {
-    // in the future this might be considered an error, but for now due to 
backwards
-    // compatibility we just fall through and execute the processor outputing 
nothing
-    // throw Exception(PROCESS_SCHEDULE_EXCEPTION, "Unrecognized output 
format: " + mode);
-  }
+  output_format_ = utils::parseEnumProperty<OutputFormat>(*context, 
OutputFormatProperty);
+  json_format_ = utils::parseEnumProperty<JsonFormat>(*context, 
JsonFormatProperty);
 
-  if ((output_.xml || output_.json) && !hMsobjsDll_) {
+  if (output_format_ != OutputFormat::PLAINTEXT && !hMsobjsDll_) {
     char systemDir[MAX_PATH];
     if (GetSystemDirectory(systemDir, sizeof(systemDir))) {
       hMsobjsDll_ = LoadLibrary((systemDir + 
std::string("\\msobjs.dll")).c_str());
@@ -611,7 +588,7 @@ nonstd::expected<EventRender, std::string> 
ConsumeWindowsEventLog::createEventRe
 
   logger_->log_trace("Finish doc traversing, performing writing...");
 
-  if (output_.plaintext) {
+  if (output_format_ == OutputFormat::PLAINTEXT || output_format_ == 
OutputFormat::BOTH) {
     logger_->log_trace("Writing event in plain text");
 
     auto& handler = getEventLogHandler(provider_name);
@@ -637,7 +614,7 @@ nonstd::expected<EventRender, std::string> 
ConsumeWindowsEventLog::createEventRe
     logger_->log_trace("Finish writing in plain text");
   }
 
-  if (output_.xml || output_.json) {
+  if (output_format_ != OutputFormat::PLAINTEXT) {
     substituteXMLPercentageItems(doc);
     logger_->log_trace("Finish substituting %% in XML");
   }
@@ -646,7 +623,7 @@ nonstd::expected<EventRender, std::string> 
ConsumeWindowsEventLog::createEventRe
     result.matched_fields = walker.getFieldValues();
   }
 
-  if (output_.xml) {
+  if (output_format_ == OutputFormat::XML || output_format_ == 
OutputFormat::BOTH) {
     logger_->log_trace("Writing event in XML");
 
     wel::XmlString writer;
@@ -657,18 +634,30 @@ nonstd::expected<EventRender, std::string> 
ConsumeWindowsEventLog::createEventRe
     logger_->log_trace("Finish writing in XML");
   }
 
-  if (output_.json.type == JSONType::Raw) {
-    logger_->log_trace("Writing event in raw JSON");
-    result.json = wel::jsonToString(wel::toRawJSON(doc));
-    logger_->log_trace("Finish writing in raw JSON");
-  } else if (output_.json.type == JSONType::Simple) {
-    logger_->log_trace("Writing event in simple JSON");
-    result.json = wel::jsonToString(wel::toSimpleJSON(doc));
-    logger_->log_trace("Finish writing in simple JSON");
-  } else if (output_.json.type == JSONType::Flattened) {
-    logger_->log_trace("Writing event in flattened JSON");
-    result.json = wel::jsonToString(wel::toFlattenedJSON(doc));
-    logger_->log_trace("Finish writing in flattened JSON");
+  if (output_format_ == OutputFormat::JSON) {
+    switch (json_format_.value()) {
+      case JsonFormat::RAW: {
+        logger_->log_trace("Writing event in raw JSON");
+        result.json = wel::jsonToString(wel::toRawJSON(doc));
+        logger_->log_trace("Finish writing in raw JSON");
+        break;
+      }
+      case JsonFormat::SIMPLE: {
+        logger_->log_trace("Writing event in simple JSON");
+        result.json = wel::jsonToString(wel::toSimpleJSON(doc));
+        logger_->log_trace("Finish writing in simple JSON");
+        break;
+      }
+      case JsonFormat::FLATTENED: {
+        logger_->log_trace("Writing event in flattened JSON");
+        result.json = wel::jsonToString(wel::toFlattenedJSON(doc));
+        logger_->log_trace("Finish writing in flattened JSON");
+        break;
+      }
+      default: {
+        gsl_Assert(false);
+      }
+    }
   }
 
   return result;
@@ -721,18 +710,18 @@ void 
ConsumeWindowsEventLog::putEventRenderFlowFileToSession(const EventRender&
     session.transfer(flow_file, Success);
   };
 
-  if (output_.xml) {
+  if (output_format_ == OutputFormat::XML || output_format_ == 
OutputFormat::BOTH) {
     logger_->log_trace("Writing rendered XML to a flow file");
     commitFlowFile(eventRender.xml, "application/xml");
   }
 
-  if (output_.plaintext) {
+  if (output_format_ == OutputFormat::PLAINTEXT || output_format_ == 
OutputFormat::BOTH) {
     logger_->log_trace("Writing rendered plain text to a flow file");
     commitFlowFile(eventRender.plaintext, "text/plain");
   }
 
-  if (output_.json) {
-    logger_->log_trace("Writing rendered %s JSON to a flow file", 
output_.json.type.toString());
+  if (output_format_ == OutputFormat::JSON) {
+    logger_->log_trace("Writing rendered %s JSON to a flow file", 
json_format_.toString());
     commitFlowFile(eventRender.json, "application/json");
   }
 }
diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.h 
b/extensions/windows-event-log/ConsumeWindowsEventLog.h
index 5a3a5b908..85c3db70f 100644
--- a/extensions/windows-event-log/ConsumeWindowsEventLog.h
+++ b/extensions/windows-event-log/ConsumeWindowsEventLog.h
@@ -74,8 +74,8 @@ class ConsumeWindowsEventLog : public core::Processor {
   EXTENSIONAPI static const core::Property ResolveAsAttributes;
   EXTENSIONAPI static const core::Property EventHeaderDelimiter;
   EXTENSIONAPI static const core::Property EventHeader;
-  EXTENSIONAPI static const core::Property OutputFormat;
-  EXTENSIONAPI static const core::Property JSONFormat;
+  EXTENSIONAPI static const core::Property OutputFormatProperty;
+  EXTENSIONAPI static const core::Property JsonFormatProperty;
   EXTENSIONAPI static const core::Property BatchCommitSize;
   EXTENSIONAPI static const core::Property BookmarkRootDirectory;
   EXTENSIONAPI static const core::Property ProcessOldEvents;
@@ -91,8 +91,8 @@ class ConsumeWindowsEventLog : public core::Processor {
         ResolveAsAttributes,
         EventHeaderDelimiter,
         EventHeader,
-        OutputFormat,
-        JSONFormat,
+        OutputFormatProperty,
+        JsonFormatProperty,
         BatchCommitSize,
         BookmarkRootDirectory,
         ProcessOldEvents,
@@ -127,14 +127,6 @@ class ConsumeWindowsEventLog : public core::Processor {
 
   nonstd::expected<std::string, std::string> renderEventAsXml(EVT_HANDLE 
event_handle);
 
-  static constexpr const char* XML = "XML";
-  static constexpr const char* Both = "Both";
-  static constexpr const char* Plaintext = "Plaintext";
-  static constexpr const char* JSON = "JSON";
-  static constexpr const char* JSONRaw = "Raw";
-  static constexpr const char* JSONSimple = "Simple";
-  static constexpr const char* JSONFlattened = "Flattened";
-
   struct TimeDiff {
     auto operator()() const {
       return int64_t{ 
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now()
 - time_).count() };
@@ -167,23 +159,21 @@ class ConsumeWindowsEventLog : public core::Processor {
   uint64_t batch_commit_size_{};
   bool cache_sid_lookups_ = true;
 
-  SMART_ENUM(JSONType,
-      (None, "None"),
-      (Raw, "Raw"),
-      (Simple, "Simple"),
-      (Flattened, "Flattened"))
-
-  struct OutputFormat {
-    bool xml{false};
-    bool plaintext{false};
-    struct JSON {
-      JSONType type{JSONType::None};
-
-      explicit operator bool() const noexcept {
-        return type != JSONType::None;
-      }
-    } json;
-  } output_;
+  SMART_ENUM(OutputFormat,
+    (XML, "XML"),
+    (BOTH, "Both"),
+    (PLAINTEXT, "Plaintext"),
+    (JSON, "JSON")
+  )
+
+  SMART_ENUM(JsonFormat,
+    (RAW, "Raw"),
+    (SIMPLE, "Simple"),
+    (FLATTENED, "Flattened")
+  )
+
+  OutputFormat output_format_;
+  JsonFormat json_format_;
 
   std::unique_ptr<Bookmark> bookmark_;
   std::mutex on_trigger_mutex_;
diff --git a/extensions/windows-event-log/tests/CWELTestUtils.h 
b/extensions/windows-event-log/tests/CWELTestUtils.h
index efe240141..e576c5b2c 100644
--- a/extensions/windows-event-log/tests/CWELTestUtils.h
+++ b/extensions/windows-event-log/tests/CWELTestUtils.h
@@ -52,9 +52,9 @@ class OutputFormatTestController : public TestController {
     auto cwel_processor = test_plan->addProcessor("ConsumeWindowsEventLog", 
"cwel");
     test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::Channel.getName(), channel_);
     test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::Query.getName(), query_);
-    test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormat.getName(), output_format_);
+    test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormatProperty.getName(), output_format_);
     if (json_format_) {
-      test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::JSONFormat.getName(), json_format_.value());
+      test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::JsonFormatProperty.getName(), json_format_.value());
     }
 
     auto dir = createTempDirectory();
diff --git a/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp 
b/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp
index 4a309986d..d91174419 100644
--- a/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp
+++ b/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp
@@ -95,7 +95,7 @@ TEST_CASE("ConsumeWindowsEventLog properties work with 
default values", "[create
     ConsumeWindowsEventLog::IdentifierFunction,
     ConsumeWindowsEventLog::ResolveAsAttributes,
     ConsumeWindowsEventLog::EventHeader,
-    ConsumeWindowsEventLog::OutputFormat,
+    ConsumeWindowsEventLog::OutputFormatProperty,
     ConsumeWindowsEventLog::BatchCommitSize,
     ConsumeWindowsEventLog::BookmarkRootDirectory,  // TODO(fgerlits): 
obsolete, see definition; remove in a later release
     ConsumeWindowsEventLog::ProcessOldEvents,
@@ -241,15 +241,15 @@ TEST_CASE("ConsumeWindowsEventLog extracts some 
attributes by default", "[onTrig
   test_plan->setProperty(logger_processor, 
LogAttribute::FlowFilesToLog.getName(), "0");
 
   SECTION("XML output") {
-    REQUIRE(test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormat.getName(), "XML"));
+    REQUIRE(test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormatProperty.getName(), "XML"));
   }
 
   SECTION("Json output") {
-    REQUIRE(test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormat.getName(), "JSON"));
+    REQUIRE(test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormatProperty.getName(), "JSON"));
   }
 
   SECTION("Plaintext output") {
-    REQUIRE(test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormat.getName(), "Plaintext"));
+    REQUIRE(test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormatProperty.getName(), "Plaintext"));
   }
 
   // 0th event, only to create a bookmark
@@ -297,7 +297,7 @@ void outputFormatSetterTestHelper(const std::string 
&output_format, int expected
   auto cwel_processor = test_plan->addProcessor("ConsumeWindowsEventLog", 
"cwel");
   test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::Channel.getName(), APPLICATION_CHANNEL);
   test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::Query.getName(), QUERY);
-  test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormat.getName(), output_format);
+  test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormatProperty.getName(), output_format);
 
   auto logger_processor = test_plan->addProcessor("LogAttribute", "logger", 
Success, true);
   test_plan->setProperty(logger_processor, 
LogAttribute::FlowFilesToLog.getName(), "0");
@@ -326,10 +326,7 @@ TEST_CASE("ConsumeWindowsEventLog output format can be 
set", "[create][output_fo
   outputFormatSetterTestHelper("XML", 1);
   outputFormatSetterTestHelper("Plaintext", 1);
   outputFormatSetterTestHelper("Both", 2);
-
-  // NOTE(fgerlits): this may be a bug, as I would expect this to throw in 
onSchedule(),
-  // but it starts merrily, just does not write flow files in either format
-  outputFormatSetterTestHelper("InvalidValue", 0);
+  REQUIRE_THROWS(outputFormatSetterTestHelper("InvalidValue", 0));
 }
 
 TEST_CASE("ConsumeWindowsEventLog prints events in plain text correctly", 
"[onTrigger]") {
@@ -433,7 +430,7 @@ void batchCommitSizeTestHelper(std::size_t num_events_read, 
std::size_t batch_co
   auto cwel_processor = test_plan->addProcessor("ConsumeWindowsEventLog", 
"cwel");
   test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::Channel.getName(), APPLICATION_CHANNEL);
   test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::Query.getName(), QUERY);
-  test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormat.getName(), "XML");
+  test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::OutputFormatProperty.getName(), "XML");
   test_plan->setProperty(cwel_processor, 
ConsumeWindowsEventLog::BatchCommitSize.getName(), 
std::to_string(batch_commit_size));
 
   {

Reply via email to