From 6566375084351b96714dd4e625107c2d1b3771e9 Mon Sep 17 00:00:00 2001 From: Martin Zink Date: Wed, 1 Apr 2026 13:03:10 +0200 Subject: [PATCH 1/3] MINIFICPP-2798 Mock library for C extensions --- .../include/utils/AttributeErrors.h | 0 .../{ => common}/include/utils/RegexUtils.h | 0 .../common}/src/utils/AttributeErrors.cpp | 0 .../{ => common}/src/utils/RegexUtils.cpp | 0 .../cpp-extension-lib/CMakeLists.txt | 2 +- .../include/api/core/ProcessContext.h | 43 ++++-- .../include/api/core/ProcessSession.h | 55 +++++-- .../include/api/core/Resource.h | 50 ++++--- .../include/api/core/logging/Logger.h | 5 +- .../include/api/utils/ProcessorConfigUtils.h | 32 ++--- .../cpp-extension-lib/include/api/utils/Ssl.h | 55 +++++++ .../include/api/utils/minifi-c-utils.h | 22 ++- .../cpp-extension-lib/mocklib/CMakeLists.txt | 24 ++++ .../mocklib/include/MockLogger.h | 36 +++++ .../mocklib/include/MockProcessContext.h | 46 ++++++ .../mocklib/include/MockProcessSession.h | 82 +++++++++++ .../mocklib/include/MockStreams.h | 97 +++++++++++++ .../mocklib/include/MockUtils.h | 35 +++++ .../mocklib/src/MockProcessContext.cpp | 50 +++++++ .../mocklib/src/MockProcessSession.cpp | 110 ++++++++++++++ .../mocklib/src/mock-minifi-c.cpp | 135 ++++++++++++++++++ .../src/core/ControllerServiceContext.cpp | 2 +- .../src/core/ProcessContext.cpp | 67 ++++++--- .../src/core/ProcessSession.cpp | 48 +++++-- .../src/core/logging/Logger.cpp | 8 +- .../processors/ExtensionInitializer.cpp | 4 +- .../processors/RunLlamaCppInference.cpp | 2 +- .../CApiExtension.cpp | 4 +- 28 files changed, 907 insertions(+), 107 deletions(-) rename core-framework/{ => common}/include/utils/AttributeErrors.h (100%) rename core-framework/{ => common}/include/utils/RegexUtils.h (100%) rename {libminifi => core-framework/common}/src/utils/AttributeErrors.cpp (100%) rename core-framework/{ => common}/src/utils/RegexUtils.cpp (100%) create mode 100644 extension-framework/cpp-extension-lib/include/api/utils/Ssl.h create mode 100644 extension-framework/cpp-extension-lib/mocklib/CMakeLists.txt create mode 100644 extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h create mode 100644 extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h create mode 100644 extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h create mode 100644 extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h create mode 100644 extension-framework/cpp-extension-lib/mocklib/include/MockUtils.h create mode 100644 extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp create mode 100644 extension-framework/cpp-extension-lib/mocklib/src/MockProcessSession.cpp create mode 100644 extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp diff --git a/core-framework/include/utils/AttributeErrors.h b/core-framework/common/include/utils/AttributeErrors.h similarity index 100% rename from core-framework/include/utils/AttributeErrors.h rename to core-framework/common/include/utils/AttributeErrors.h diff --git a/core-framework/include/utils/RegexUtils.h b/core-framework/common/include/utils/RegexUtils.h similarity index 100% rename from core-framework/include/utils/RegexUtils.h rename to core-framework/common/include/utils/RegexUtils.h diff --git a/libminifi/src/utils/AttributeErrors.cpp b/core-framework/common/src/utils/AttributeErrors.cpp similarity index 100% rename from libminifi/src/utils/AttributeErrors.cpp rename to core-framework/common/src/utils/AttributeErrors.cpp diff --git a/core-framework/src/utils/RegexUtils.cpp b/core-framework/common/src/utils/RegexUtils.cpp similarity index 100% rename from core-framework/src/utils/RegexUtils.cpp rename to core-framework/common/src/utils/RegexUtils.cpp diff --git a/extension-framework/cpp-extension-lib/CMakeLists.txt b/extension-framework/cpp-extension-lib/CMakeLists.txt index 6b22dd980a..f1161279bf 100644 --- a/extension-framework/cpp-extension-lib/CMakeLists.txt +++ b/extension-framework/cpp-extension-lib/CMakeLists.txt @@ -24,4 +24,4 @@ target_include_directories(minifi-cpp-extension-lib PUBLIC include) target_link_libraries(minifi-cpp-extension-lib PUBLIC minifi-core-framework-common minifi-c-api) add_subdirectory(libtest) - +add_subdirectory(mocklib) diff --git a/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h b/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h index 6f012d719a..ee9eb0f727 100644 --- a/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h +++ b/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h @@ -1,5 +1,5 @@ /** -* Licensed to the Apache Software Foundation (ASF) under one or more + * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 @@ -20,23 +20,48 @@ #include #include +#include "api/core/FlowFile.h" +#include "api/utils/Ssl.h" #include "minifi-c.h" #include "minifi-cpp/core/PropertyDefinition.h" -#include "api/core/FlowFile.h" namespace org::apache::nifi::minifi::api::core { class ProcessContext { public: - explicit ProcessContext(MinifiProcessContext* impl): impl_(impl) {} + virtual ~ProcessContext() noexcept = default; + + ProcessContext() = default; + ProcessContext(const ProcessContext&) = delete; + ProcessContext(ProcessContext&&) = delete; + ProcessContext& operator=(const ProcessContext&) = delete; + ProcessContext& operator=(ProcessContext&&) = delete; + + [[nodiscard]] virtual std::expected getProperty(const minifi::core::PropertyReference& prop, + const FlowFile* ff) const = 0; + [[nodiscard]] virtual std::expected getControllerService(std::string_view name, + std::string_view type) const = 0; + [[nodiscard]] virtual bool hasNonEmptyProperty(std::string_view name) const = 0; + [[nodiscard]] virtual std::map getDynamicProperties(const FlowFile* flow_file) const = 0; + + [[nodiscard]] virtual std::expected getSslData(std::string_view name) const = 0; +}; + +class CffiProcessContext : public ProcessContext { + public: + explicit CffiProcessContext(MinifiProcessContext* impl) : impl_(impl) {} - std::expected getProperty(std::string_view name, const FlowFile* flow_file = nullptr) const; - std::expected getProperty(const minifi::core::PropertyReference& property_reference, const FlowFile* flow_file = nullptr) const { - return getProperty(property_reference.name, flow_file); - } - [[nodiscard]] std::expected getControllerService(std::string_view controller_service_name, std::string_view controller_service_class) const; + [[nodiscard]] std::expected getProperty(const minifi::core::PropertyReference& property_reference, + const FlowFile* flow_file) const override; + [[nodiscard]] std::expected getControllerService(std::string_view name, + std::string_view type) const override; + [[nodiscard]] std::map getDynamicProperties(const FlowFile* flow_file) const override; + [[nodiscard]] bool hasNonEmptyProperty(std::string_view name) const override; - [[nodiscard]] bool hasNonEmptyProperty(std::string_view name) const; + [[nodiscard]] std::expected getSslData(std::string_view name) const override; + + private: + [[nodiscard]] std::expected getProperty(std::string_view name, const FlowFile* flow_file) const; private: MinifiProcessContext* impl_; diff --git a/extension-framework/cpp-extension-lib/include/api/core/ProcessSession.h b/extension-framework/cpp-extension-lib/include/api/core/ProcessSession.h index e3e8122497..1ef50770d9 100644 --- a/extension-framework/cpp-extension-lib/include/api/core/ProcessSession.h +++ b/extension-framework/cpp-extension-lib/include/api/core/ProcessSession.h @@ -29,23 +29,54 @@ namespace org::apache::nifi::minifi::api::core { class ProcessSession { public: - explicit ProcessSession(MinifiProcessSession* impl): impl_(impl) {} + virtual ~ProcessSession() = default; - FlowFile create(const FlowFile* parent = nullptr); - FlowFile get(); - void transfer(FlowFile ff, const minifi::core::Relationship& relationship); - void remove(FlowFile ff); - void write(FlowFile& flow, const io::OutputStreamCallback& callback); - void read(FlowFile& flow, const io::InputStreamCallback& callback); + ProcessSession() = default; - void setAttribute(FlowFile& ff, std::string_view key, std::string value); - void removeAttribute(FlowFile& ff, std::string_view key); - std::optional getAttribute(FlowFile& ff, std::string_view key); - std::map getAttributes(FlowFile& ff); + ProcessSession(const ProcessSession&) = delete; + ProcessSession(ProcessSession&&) = delete; + ProcessSession& operator=(const ProcessSession&) = delete; + ProcessSession& operator=(ProcessSession&&) = delete; + + virtual FlowFile create(const FlowFile* parent = nullptr) = 0; + virtual FlowFile get() = 0; + + virtual void penalize(FlowFile& ff) = 0; + virtual void transfer(FlowFile ff, const minifi::core::Relationship& relationship) = 0; + virtual void remove(FlowFile ff) = 0; + virtual void write(FlowFile& flow, const io::OutputStreamCallback& callback) = 0; + virtual void read(FlowFile& flow, const io::InputStreamCallback& callback) = 0; + + virtual void setAttribute(FlowFile& ff, std::string_view key, std::string value) = 0; + virtual void removeAttribute(FlowFile& ff, std::string_view key) = 0; + [[nodiscard]] virtual std::optional getAttribute(FlowFile& ff, std::string_view key) = 0; + [[nodiscard]] virtual std::map getAttributes(const FlowFile& ff) const = 0; + [[nodiscard]] virtual std::string getFlowFileId(const FlowFile& ff) const = 0; + [[nodiscard]] virtual uint64_t getFlowFileSize(const FlowFile& ff) const = 0; void writeBuffer(FlowFile& flow_file, std::span buffer); void writeBuffer(FlowFile& flow_file, std::span buffer); - std::vector readBuffer(FlowFile& flow_file); + [[nodiscard]] std::vector readBuffer(FlowFile& flow_file); +}; + +class CffiProcessSession : public ProcessSession { + public: + explicit CffiProcessSession(MinifiProcessSession* impl): impl_(impl) {} + + FlowFile create(const FlowFile* parent = nullptr) override; + FlowFile get() override; + void penalize(FlowFile& ff) override; + void transfer(FlowFile ff, const minifi::core::Relationship& relationship) override; + void remove(FlowFile ff) override; + void write(FlowFile& flow, const io::OutputStreamCallback& callback) override; + void read(FlowFile& flow, const io::InputStreamCallback& callback) override; + + void setAttribute(FlowFile& ff, std::string_view key, std::string value) override; + void removeAttribute(FlowFile& ff, std::string_view key) override; + [[nodiscard]] std::optional getAttribute(FlowFile& ff, std::string_view key) override; + [[nodiscard]] std::map getAttributes(const FlowFile& ff) const override; + [[nodiscard]] std::string getFlowFileId(const FlowFile& ff) const override; + [[nodiscard]] uint64_t getFlowFileSize(const FlowFile& ff) const override; private: MinifiProcessSession* impl_; diff --git a/extension-framework/cpp-extension-lib/include/api/core/Resource.h b/extension-framework/cpp-extension-lib/include/api/core/Resource.h index 8187605e51..60766741cb 100644 --- a/extension-framework/cpp-extension-lib/include/api/core/Resource.h +++ b/extension-framework/cpp-extension-lib/include/api/core/Resource.h @@ -49,17 +49,17 @@ void useProcessorClassDefinition(Fn&& fn) { std::vector dynamic_properties; for (auto& prop : Class::DynamicProperties) { dynamic_properties.push_back(MinifiDynamicPropertyDefinition { - .name = utils::toStringView(prop.name), - .value = utils::toStringView(prop.value), - .description = utils::toStringView(prop.description), + .name = utils::minifiStringView(prop.name), + .value = utils::minifiStringView(prop.value), + .description = utils::minifiStringView(prop.description), .supports_expression_language = prop.supports_expression_language }); } std::vector relationships; for (auto& rel : Class::Relationships) { relationships.push_back(MinifiRelationshipDefinition{ - .name = utils::toStringView(rel.name), - .description = utils::toStringView(rel.description) + .name = utils::minifiStringView(rel.name), + .description = utils::minifiStringView(rel.description) }); } std::vector> attribute_relationships_cache; @@ -67,20 +67,20 @@ void useProcessorClassDefinition(Fn&& fn) { for (auto& attr : Class::OutputAttributes) { std::vector rel_cache; for (auto& rel : attr.relationships) { - rel_cache.push_back(utils::toStringView(rel.name)); + rel_cache.push_back(utils::minifiStringView(rel.name)); } output_attributes.push_back(MinifiOutputAttributeDefinition { - .name = utils::toStringView(attr.name), + .name = utils::minifiStringView(attr.name), .relationships_count = gsl::narrow(attr.relationships.size()), .relationships_ptr = rel_cache.data(), - .description = utils::toStringView(attr.description) + .description = utils::minifiStringView(attr.description) }); attribute_relationships_cache.push_back(std::move(rel_cache)); } MinifiProcessorClassDefinition definition{ - .full_name = utils::toStringView(full_name), - .description = utils::toStringView(Class::Description), + .full_name = utils::minifiStringView(full_name), + .description = utils::minifiStringView(Class::Description), .class_properties_count = gsl::narrow(class_properties.size()), .class_properties_ptr = class_properties.data(), .dynamic_properties_count = gsl::narrow(dynamic_properties.size()), @@ -100,7 +100,7 @@ void useProcessorClassDefinition(Fn&& fn) { return new Class{minifi::core::ProcessorMetadata{ .uuid = minifi::utils::Identifier::parse(std::string{metadata.uuid.data, metadata.uuid.length}).value(), .name = std::string{metadata.name.data, metadata.name.length}, - .logger = std::make_shared(metadata.logger)}}; + .logger = std::make_shared(metadata.logger)}}; } catch (...) { return nullptr; } }, .destroy = [] (MINIFI_OWNED void* self) -> void { @@ -110,8 +110,8 @@ void useProcessorClassDefinition(Fn&& fn) { return static_cast(self)->getTriggerWhenEmpty(); }, .onTrigger = [] (void* self, MinifiProcessContext* context, MinifiProcessSession* session) -> MinifiStatus { - ProcessContext context_wrapper(context); - ProcessSession session_wrapper(session); + CffiProcessContext context_wrapper(context); + CffiProcessSession session_wrapper(session); try { return static_cast(self)->onTrigger(context_wrapper, session_wrapper); } catch (...) { @@ -119,7 +119,7 @@ void useProcessorClassDefinition(Fn&& fn) { } }, .onSchedule = [] (void* self, MinifiProcessContext* context) -> MinifiStatus { - ProcessContext context_wrapper(context); + CffiProcessContext context_wrapper(context); try { return static_cast(self)->onSchedule(context_wrapper); } catch (...) { @@ -136,7 +136,7 @@ void useProcessorClassDefinition(Fn&& fn) { std::vector names; std::vector values; for (auto& [name, val] : metrics) { - names.push_back(utils::toStringView(name)); + names.push_back(utils::minifiStringView(name)); values.push_back(val); } return MinifiPublishedMetricsCreate(gsl::narrow(metrics.size()), names.data(), values.data()); @@ -155,8 +155,8 @@ void useControllerServiceClassDefinition(Fn&& fn) { std::vector class_properties = utils::toProperties(Class::Properties, string_vector_cache); - MinifiControllerServiceClassDefinition definition{.full_name = utils::toStringView(full_name), - .description = utils::toStringView(Class::Description), + MinifiControllerServiceClassDefinition definition{.full_name = utils::minifiStringView(full_name), + .description = utils::minifiStringView(Class::Description), .class_properties_count = gsl::narrow(class_properties.size()), .class_properties_ptr = class_properties.data(), @@ -166,7 +166,7 @@ void useControllerServiceClassDefinition(Fn&& fn) { return new Class{minifi::core::ControllerServiceMetadata{ .uuid = minifi::utils::Identifier::parse(std::string{metadata.uuid.data, metadata.uuid.length}).value(), .name = std::string{metadata.name.data, metadata.name.length}, - .logger = std::make_shared(metadata.logger)}}; + .logger = std::make_shared(metadata.logger)}}; } catch (...) { return nullptr; } }, .destroy = [](MINIFI_OWNED void* self) -> void { delete static_cast(self); }, @@ -186,4 +186,18 @@ void useControllerServiceClassDefinition(Fn&& fn) { fn(definition); } +template +void registerProcessors(MinifiExtension* extension) { + (core::useProcessorClassDefinition([&](const MinifiProcessorClassDefinition& definition) { + MinifiRegisterProcessor(extension, &definition); + }), ...); +} + +template +void registerControllerServices(MinifiExtension* extension) { + (core::useControllerServiceClassDefinition([&](const MinifiControllerServiceClassDefinition& definition) { + MinifiRegisterControllerService(extension, &definition); + }), ...); +} + } // namespace org::apache::nifi::minifi::api::core diff --git a/extension-framework/cpp-extension-lib/include/api/core/logging/Logger.h b/extension-framework/cpp-extension-lib/include/api/core/logging/Logger.h index ada9e51785..5a44013445 100644 --- a/extension-framework/cpp-extension-lib/include/api/core/logging/Logger.h +++ b/extension-framework/cpp-extension-lib/include/api/core/logging/Logger.h @@ -20,15 +20,14 @@ #include #include -#include "fmt/chrono.h" #include "minifi-c.h" #include "minifi-cpp/core/logging/Logger.h" namespace org::apache::nifi::minifi::api::core::logging { -class Logger : public minifi::core::logging::Logger { +class CffiLogger : public minifi::core::logging::Logger { public: - explicit Logger(MinifiLogger* impl): impl_(impl) {} + explicit CffiLogger(MinifiLogger* impl): impl_(impl) {} void set_max_log_size(int size) override; void log_string(minifi::core::logging::LOG_LEVEL level, std::string str) override; diff --git a/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h b/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h index a73dd75498..db44e1cd5e 100644 --- a/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h +++ b/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h @@ -32,47 +32,47 @@ namespace org::apache::nifi::minifi::api::utils { inline std::string parseProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::orThrow(fmt::format("Expected valid value from \"{}\"", property.name)); } inline bool parseBoolProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::andThen(parsing::parseBool) | minifi::utils::orThrow(fmt::format("Expected parsable bool from \"{}\"", property.name)); } inline uint64_t parseU64Property(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::andThen(parsing::parseIntegral) | minifi::utils::orThrow(fmt::format("Expected parsable uint64_t from \"{}\"", property.name)); } inline int64_t parseI64Property(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::andThen(parsing::parseIntegral) | minifi::utils::orThrow(fmt::format("Expected parsable int64_t from \"{}\"", property.name)); } inline std::chrono::milliseconds parseDurationProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::andThen(parsing::parseDuration) | minifi::utils::orThrow(fmt::format("Expected parsable duration from \"{}\"", property.name)); } inline uint64_t parseDataSizeProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::andThen(parsing::parseDataSize) | minifi::utils::orThrow(fmt::format("Expected parsable data size from \"{}\"", property.name)); } inline std::optional parseOptionalProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - return ctx.getProperty(property.name, flow_file) + return ctx.getProperty(property, flow_file) | minifi::utils::toOptional(); } inline std::optional parseOptionalBoolProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - if (const auto property_str = ctx.getProperty(property.name, flow_file)) { + if (const auto property_str = ctx.getProperty(property, flow_file)) { return parsing::parseBool(*property_str) | minifi::utils::orThrow(fmt::format("Expected parsable bool from \"{}\"", property.name)); } @@ -80,7 +80,7 @@ inline std::optional parseOptionalBoolProperty(const core::ProcessContext& } inline std::optional parseOptionalU64Property(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - if (const auto property_str = ctx.getProperty(property.name, flow_file)) { + if (const auto property_str = ctx.getProperty(property, flow_file)) { if (property_str->empty()) { return std::nullopt; } @@ -92,7 +92,7 @@ inline std::optional parseOptionalU64Property(const core::ProcessConte } inline std::optional parseOptionalI64Property(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - if (const auto property_str = ctx.getProperty(property.name, flow_file)) { + if (const auto property_str = ctx.getProperty(property, flow_file)) { if (property_str->empty()) { return std::nullopt; } @@ -106,7 +106,7 @@ inline std::optional parseOptionalI64Property(const core::ProcessContex inline std::optional parseOptionalDurationProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - if (const auto property_str = ctx.getProperty(property.name, flow_file)) { + if (const auto property_str = ctx.getProperty(property, flow_file)) { if (property_str->empty()) { return std::nullopt; } @@ -118,7 +118,7 @@ inline std::optional parseOptionalDurationProperty(co } inline std::optional parseOptionalDataSizeProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - if (const auto property_str = ctx.getProperty(property.name, flow_file)) { + if (const auto property_str = ctx.getProperty(property, flow_file)) { if (property_str->empty()) { return std::nullopt; } @@ -130,7 +130,7 @@ inline std::optional parseOptionalDataSizeProperty(const core::Process } inline std::optional parseOptionalFloatProperty(const core::ProcessContext& ctx, const minifi::core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) { - if (const auto property_str = ctx.getProperty(property.name, flow_file)) { + if (const auto property_str = ctx.getProperty(property, flow_file)) { if (property_str->empty()) { return std::nullopt; } @@ -142,7 +142,7 @@ inline std::optional parseOptionalFloatProperty(const core::ProcessContex template T parseEnumProperty(const core::ProcessContext& context, const minifi::core::PropertyReference& prop, const core::FlowFile* flow_file = nullptr) { - const auto enum_str = context.getProperty(prop.name, flow_file); + const auto enum_str = context.getProperty(prop, flow_file); if (!enum_str) { throw Exception(PROCESS_SCHEDULE_EXCEPTION, "Property '" + std::string(prop.name) + "' is missing"); } @@ -155,7 +155,7 @@ T parseEnumProperty(const core::ProcessContext& context, const minifi::core::Pro template std::optional parseOptionalEnumProperty(const core::ProcessContext& context, const minifi::core::PropertyReference& prop) { - const auto enum_str = context.getProperty(prop.name); + const auto enum_str = context.getProperty(prop, nullptr); if (!enum_str) { return std::nullopt; @@ -169,7 +169,7 @@ std::optional parseOptionalEnumProperty(const core::ProcessContext& context, template ControllerServiceType* parseOptionalControllerService(const core::ProcessContext& context, const minifi::core::PropertyReference& prop) { - const auto controller_service_name = context.getProperty(prop.name); + const auto controller_service_name = context.getProperty(prop, nullptr); if (!controller_service_name || controller_service_name->empty()) { return nullptr; } diff --git a/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h b/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h new file mode 100644 index 0000000000..eba0e16705 --- /dev/null +++ b/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include +#include + +#include "utils/Enum.h" + +namespace org::apache::nifi::minifi::api::utils::net { + +enum class ClientAuthOption { + NONE, + WANT, + REQUIRED +}; + +struct SslData { + std::filesystem::path ca_loc; + std::filesystem::path cert_loc; + std::filesystem::path key_loc; + std::string key_pw; + + bool isValid() const { + return !cert_loc.empty() && !key_loc.empty(); + } +}; + +struct SslServerOptions { + SslData cert_data; + ClientAuthOption client_auth_option; + + SslServerOptions(SslData cert_data, ClientAuthOption client_auth_option) + : cert_data(cert_data), + client_auth_option(client_auth_option) {} +}; + + +} // namespace org::apache::nifi::minifi::api::utils::net diff --git a/extension-framework/cpp-extension-lib/include/api/utils/minifi-c-utils.h b/extension-framework/cpp-extension-lib/include/api/utils/minifi-c-utils.h index 43fb283067..227ad4c808 100644 --- a/extension-framework/cpp-extension-lib/include/api/utils/minifi-c-utils.h +++ b/extension-framework/cpp-extension-lib/include/api/utils/minifi-c-utils.h @@ -32,10 +32,18 @@ namespace org::apache::nifi::minifi::api::utils { -inline MinifiStringView toStringView(std::string_view str) { +inline MinifiStringView minifiStringView(const std::string_view str) { return MinifiStringView{.data = str.data(), .length = str.length()}; } +inline std::string toString(const MinifiStringView sv) { + return {sv.data, sv.length}; +} + +inline std::string_view toStringView(const MinifiStringView sv) { + return {sv.data, sv.length}; +} + template std::string classNameWithDots() { std::string class_name{minifi::core::className()}; @@ -59,27 +67,27 @@ inline std::vector toProperties(std::span sv_cache; const size_t allowed_values_begin = sv_cache.size(); for (auto& allowed_value : prop.allowed_values) { - sv_cache.emplace_back(toStringView(allowed_value)); + sv_cache.emplace_back(minifiStringView(allowed_value)); } const std::optional allowed_types_begin = [&] () -> std::optional { if (prop.allowed_types.empty()) { return std::nullopt; } gsl_Expects(prop.allowed_types.size() == 1); - sv_cache.emplace_back(toStringView(prop.allowed_types[0])); + sv_cache.emplace_back(minifiStringView(prop.allowed_types[0])); return sv_cache.size() - 1; }(); const std::optional default_value_begin = [&] () -> std::optional { if (!prop.default_value) { return std::nullopt; } - sv_cache.emplace_back(toStringView(*prop.default_value)); + sv_cache.emplace_back(minifiStringView(*prop.default_value)); return sv_cache.size() - 1; }(); properties.push_back(MinifiPropertyDefinition{ - .name = toStringView(prop.name), - .display_name = toStringView(prop.display_name), - .description = toStringView(prop.description), + .name = minifiStringView(prop.name), + .display_name = minifiStringView(prop.display_name), + .description = minifiStringView(prop.description), .is_required = prop.is_required, .is_sensitive = prop.is_sensitive, diff --git a/extension-framework/cpp-extension-lib/mocklib/CMakeLists.txt b/extension-framework/cpp-extension-lib/mocklib/CMakeLists.txt new file mode 100644 index 0000000000..f93870f375 --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/CMakeLists.txt @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +file(GLOB SRC_FILES CONFIGURE_DEPENDS "src/*.cpp") + +add_library(libmock-minifi STATIC ${SRC_FILES}) +target_link_libraries(libmock-minifi PUBLIC minifi-cpp-extension-lib minifi-core-framework-common minifi-c-api) +target_include_directories(libmock-minifi PUBLIC include) diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h b/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h new file mode 100644 index 0000000000..56be27b966 --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "minifi-cpp/core/logging/Logger.h" + +namespace org::apache::nifi::minifi::mock { +class MockLogger : public core::logging::Logger { + public: + void set_max_log_size(int) override {} + void log_string(const core::logging::LOG_LEVEL level, std::string s) override { logs_[level].emplace_back(std::move(s)); } + [[nodiscard]] bool should_log(const core::logging::LOG_LEVEL level) override { return level > log_level_; } + [[nodiscard]] core::logging::LOG_LEVEL level() const override { return log_level_; } + + core::logging::LOG_LEVEL log_level_ = core::logging::LOG_LEVEL::trace; + std::map> logs_; +}; +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h new file mode 100644 index 0000000000..62a0bc57af --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +#include "MockUtils.h" +#include "api/core/ProcessContext.h" + +namespace org::apache::nifi::minifi::mock { +class MockProcessContext : public api::core::ProcessContext { + public: + using ProcessContext::ProcessContext; + + [[nodiscard]] std::expected getProperty(const core::PropertyReference& property_reference, + const api::core::FlowFile* flow_file) const override; + [[nodiscard]] std::expected getControllerService(std::string_view controller_service_name, + std::string_view controller_service_class) const override; + [[nodiscard]] std::map getDynamicProperties(const api::core::FlowFile* flow_file) const override; + [[nodiscard]] bool hasNonEmptyProperty(std::string_view name) const override; + + [[nodiscard]] std::expected getSslData(std::string_view name) const override; + + std::map> properties_; + + private: + [[nodiscard]] std::expected getProperty(std::string_view name, + const api::core::FlowFile* flow_file) const; +}; + +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h new file mode 100644 index 0000000000..fa53671a9c --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +#include "MockUtils.h" +#include "api/core/ProcessSession.h" +#include "range/v3/range/conversion.hpp" +#include "range/v3/view/transform.hpp" + +namespace org::apache::nifi::minifi::mock { +struct MockFlowFileData { + explicit MockFlowFileData(std::string content_str) { + this->content = content_str + | ranges::views::transform([](char c) { return static_cast(c); }) + | ranges::to>(); + } + + ~MockFlowFileData() = default; + + MockFlowFileData() = default; + MockFlowFileData(const MockFlowFileData&) = default; + MockFlowFileData(MockFlowFileData&&) = default; + MockFlowFileData& operator=(const MockFlowFileData&) = default; + MockFlowFileData& operator=(MockFlowFileData&&) = default; + + std::map attributes; + std::vector content; + bool is_penalized = false; + std::string id; +}; + +class MockProcessSession : public api::core::ProcessSession { + public: + MockProcessSession() = default; + MockProcessSession(const MockProcessSession&) = delete; + MockProcessSession& operator=(const MockProcessSession&) = delete; + MockProcessSession(const MockProcessSession&&) = delete; + MockProcessSession& operator=(const MockProcessSession&&) = delete; + + ~MockProcessSession() override; + + api::core::FlowFile create(const api::core::FlowFile* parent) override; + api::core::FlowFile get() override; + void penalize(api::core::FlowFile& ff) override; + void transfer(api::core::FlowFile ff, const minifi::core::Relationship& relationship) override; + void remove(api::core::FlowFile ff) override; + void write(api::core::FlowFile& ff, const io::OutputStreamCallback& callback) override; + void read(api::core::FlowFile& ff, const io::InputStreamCallback& callback) override; + void setAttribute(api::core::FlowFile& ff, std::string_view key, std::string value) override; + void removeAttribute(api::core::FlowFile& ff, std::string_view key) override; + std::optional getAttribute(api::core::FlowFile& ff, std::string_view key) override; + [[nodiscard]] std::map getAttributes(const api::core::FlowFile& ff) const override; + [[nodiscard]] std::string getFlowFileId(const api::core::FlowFile& ff) const override; + [[nodiscard]] uint64_t getFlowFileSize(const api::core::FlowFile& ff) const override; + + void addInputFlowFile(MockFlowFileData flow_file_data); + + private: + std::vector input_flow_files_; + std::map flow_file_datas; + std::map> transferred_flow_files_; + std::vector removed_flow_files_; +}; + +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h b/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h new file mode 100644 index 0000000000..73352daf74 --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "minifi-cpp/io/InputStream.h" +#include "minifi-cpp/io/OutputStream.h" + +namespace org::apache::nifi::minifi::mock { + +class MockOutputStream : public io::OutputStream { + public: + explicit MockOutputStream(std::vector& container) : container_(container) {} + + size_t write(const uint8_t* value, const size_t len) override { + if (len == 0 || value == nullptr) { return 0; } + + if (offset_ + len > container_.size()) { container_.resize(offset_ + len); } + + std::memcpy(container_.data() + offset_, value, len); + offset_ += len; + return len; + } + + void seek(const size_t offset) override { offset_ = offset; } + + [[nodiscard]] size_t tell() const override { return offset_; } + + [[nodiscard]] std::span getBuffer() const override { return {container_.data(), container_.size()}; } + + int initialize() override { + offset_ = 0; + return 0; + } + + void close() override {} + + private: + std::vector& container_; + size_t offset_ = 0; +}; + +class MockInputStream : public io::InputStream { + public: + explicit MockInputStream(const std::vector& container) : container_(container) {} + + size_t read(std::span out_buffer) override { + if (out_buffer.empty() || offset_ >= container_.size()) { return 0; } + + const size_t readable = container_.size() - offset_; + const size_t len = std::min(out_buffer.size(), readable); + + std::memcpy(out_buffer.data(), container_.data() + offset_, len); + offset_ += len; + return len; + } + + void seek(const size_t offset) override { offset_ = std::min(offset, container_.size()); } + + [[nodiscard]] size_t tell() const override { return offset_; } + + [[nodiscard]] size_t size() const override { return container_.size(); } + + [[nodiscard]] std::span getBuffer() const override { return {container_.data(), container_.size()}; } + + int initialize() override { + offset_ = 0; + return 0; + } + + void close() override {} + + private: + const std::vector& container_; + size_t offset_ = 0; +}; + +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockUtils.h b/extension-framework/cpp-extension-lib/mocklib/include/MockUtils.h new file mode 100644 index 0000000000..471df81893 --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockUtils.h @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "MockLogger.h" +#include "minifi-cpp/core/ProcessorMetadata.h" + +struct MinifiFlowFile{}; + +namespace org::apache::nifi::minifi::mock { +inline core::ProcessorMetadata getMockMetadata() { + return core::ProcessorMetadata{.uuid = utils::Identifier{}, .name = "Processor", .logger = std::make_shared()}; +} + +inline core::ProcessorMetadata metadataWithLogger(std::shared_ptr logger) { + return core::ProcessorMetadata{.uuid = utils::Identifier{}, .name = "Processor", .logger = std::move(logger)}; +} +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp b/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp new file mode 100644 index 0000000000..b8bb1e5fc6 --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MockProcessContext.h" + +#include "utils/PropertyErrors.h" + +namespace org::apache::nifi::minifi::mock { +std::expected MockProcessContext::getProperty(const std::string_view name, const api::core::FlowFile*) const { + if (!properties_.contains(name)) { return std::unexpected{make_error_code(core::PropertyErrorCode::PropertyNotSet)}; } + return properties_.at(std::string(name)); +} + +std::expected MockProcessContext::getProperty(const minifi::core::PropertyReference& property_reference, + const api::core::FlowFile* flow_file) const { + if (auto property = getProperty(property_reference.name, flow_file)) { return property; } + if (property_reference.default_value) { return std::string{*property_reference.default_value}; } + return std::unexpected{make_error_code(core::PropertyErrorCode::PropertyNotSet)}; +} + +std::expected MockProcessContext::getControllerService(std::string_view, std::string_view) const { + return nullptr; +} + +std::map MockProcessContext::getDynamicProperties(const api::core::FlowFile*) const { + return {}; +} + +bool MockProcessContext::hasNonEmptyProperty(const std::string_view name) const { + return properties_.contains(name); +} + +std::expected MockProcessContext::getSslData(std::string_view) const { + return api::utils::net::SslData{}; +} +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/src/MockProcessSession.cpp b/extension-framework/cpp-extension-lib/mocklib/src/MockProcessSession.cpp new file mode 100644 index 0000000000..2329808f7e --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/src/MockProcessSession.cpp @@ -0,0 +1,110 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MockProcessSession.h" + +#include "MockStreams.h" + +namespace org::apache::nifi::minifi::mock { + +MockProcessSession::~MockProcessSession() { + // api::core::FlowFile requires that somebody takes ownership before it goes out of scope + // the tested processor should either remove or transfer all FlowFiles it handles + for (auto& ff : removed_flow_files_) { + delete ff.release(); // NOLINT(cppcoreguidelines-owning-memory) + } + for (auto& ffs : transferred_flow_files_ | std::views::values) { + for (auto& ff : ffs) { + delete ff.release(); // NOLINT(cppcoreguidelines-owning-memory) + } + } +} + +api::core::FlowFile MockProcessSession::create(const api::core::FlowFile*) { + auto new_ff = api::core::FlowFile{new MinifiFlowFile}; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + flow_file_datas[new_ff.get()]; + return new_ff; +} +api::core::FlowFile MockProcessSession::get() { + if (input_flow_files_.empty()) { return nullptr; } + + auto ff = std::move(input_flow_files_.back()); + input_flow_files_.pop_back(); + flow_file_datas[ff.get()]; + + return ff; +} + +void MockProcessSession::penalize(api::core::FlowFile& ff) { + auto& flow_file_data = flow_file_datas.at(ff.get()); + flow_file_data.is_penalized = true; +} + +void MockProcessSession::transfer(api::core::FlowFile ff, const minifi::core::Relationship& relationship) { + transferred_flow_files_[relationship.getName()].push_back(std::move(ff)); +} + +void MockProcessSession::remove(api::core::FlowFile ff) { + removed_flow_files_.push_back(std::move(ff)); +} + +void MockProcessSession::write(api::core::FlowFile& ff, const io::OutputStreamCallback& callback) { + auto& flow_file_data = flow_file_datas.at(ff.get()); + const auto stream = std::make_shared(flow_file_data.content); + callback(stream); +} + +void MockProcessSession::read(api::core::FlowFile& ff, const io::InputStreamCallback& callback) { + auto& flow_file_data = flow_file_datas.at(ff.get()); + const auto stream = std::make_shared(flow_file_data.content); + callback(stream); +} + +void MockProcessSession::setAttribute(api::core::FlowFile& ff, std::string_view key, std::string value) { + auto& attributes = flow_file_datas.at(ff.get()).attributes; + attributes[std::string(key)] = std::move(value); +} + +void MockProcessSession::removeAttribute(api::core::FlowFile& ff, std::string_view key) { + auto& attributes = flow_file_datas.at(ff.get()).attributes; + attributes.erase(std::string(key)); +} + +std::optional MockProcessSession::getAttribute(api::core::FlowFile& ff, std::string_view key) { + auto& attributes = flow_file_datas.at(ff.get()).attributes; + if (const auto it = attributes.find(std::string(key)); it != attributes.end()) { return it->second; } + return std::nullopt; +} + +std::map MockProcessSession::getAttributes(const api::core::FlowFile& ff) const { + return flow_file_datas.at(ff.get()).attributes; +} + +std::string MockProcessSession::getFlowFileId(const api::core::FlowFile& ff) const { + return flow_file_datas.at(ff.get()).id; +} + +uint64_t MockProcessSession::getFlowFileSize(const api::core::FlowFile& ff) const { + return flow_file_datas.at(ff.get()).content.size(); +} + +void MockProcessSession::addInputFlowFile(MockFlowFileData flow_file_data) { + auto new_ff = api::core::FlowFile{new MinifiFlowFile}; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + flow_file_datas.emplace(new_ff.get(), std::move(flow_file_data)); + input_flow_files_.push_back(std::move(new_ff)); +} +} // namespace org::apache::nifi::minifi::mock diff --git a/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp b/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp new file mode 100644 index 0000000000..8b48d0d578 --- /dev/null +++ b/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp @@ -0,0 +1,135 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "minifi-c.h" + +MinifiExtension* MINIFI_REGISTER_EXTENSION_FN(MinifiExtensionContext*, const MinifiExtensionDefinition*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiRegisterProcessor(MinifiExtension*, const MinifiProcessorClassDefinition*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiRegisterControllerService(MinifiExtension*, const MinifiControllerServiceClassDefinition*) { + throw std::runtime_error("Not implemented"); +} + +MINIFI_OWNED MinifiPublishedMetrics* MinifiPublishedMetricsCreate(size_t, const MinifiStringView*, const double*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessContextGetProperty(MinifiProcessContext*, MinifiStringView, MinifiFlowFile*, + void (*)(void* user_ctx, MinifiStringView property_value), void*) { + throw std::runtime_error("Not implemented"); +} +MinifiBool MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext*, MinifiStringView) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessContextGetControllerService(MinifiProcessContext*, MinifiStringView, MinifiStringView, MinifiControllerService**) { + throw std::runtime_error("Not implemented"); +} +void MinifiProcessContextGetDynamicProperties(MinifiProcessContext*, + void (*)(void* user_ctx, MinifiStringView dynamic_property_name, MinifiStringView dynamic_property_value), void*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessContextGetSslData(MinifiProcessContext*, MinifiStringView, + void (*)(void* user_ctx, const MinifiSslData& ssl_data), void*) { + throw std::runtime_error("Not implemented"); +} + +void MinifiLoggerSetMaxLogSize(MinifiLogger*, int32_t) { + throw std::runtime_error("Not implemented"); +} +void MinifiLoggerLogString(MinifiLogger*, MinifiLogLevel, MinifiStringView) { + throw std::runtime_error("Not implemented"); +} +MinifiBool MinifiLoggerShouldLog(MinifiLogger*, MinifiLogLevel) { + throw std::runtime_error("Not implemented"); +} +MinifiLogLevel MinifiLoggerLevel(MinifiLogger*) { + throw std::runtime_error("Not implemented"); +} + +MINIFI_OWNED MinifiFlowFile* MinifiProcessSessionGet(MinifiProcessSession*) { + throw std::runtime_error("Not implemented"); +} +MINIFI_OWNED MinifiFlowFile* MinifiProcessSessionCreate(MinifiProcessSession*, MinifiFlowFile*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessSessionPenalize(MinifiProcessSession*, MinifiFlowFile*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessSessionTransfer(MinifiProcessSession*, MINIFI_OWNED MinifiFlowFile*, MinifiStringView) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessSessionRemove(MinifiProcessSession*, MINIFI_OWNED MinifiFlowFile*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessSessionRead(MinifiProcessSession*, MinifiFlowFile*, int64_t (*)(void* user_ctx, MinifiInputStream*), void*) { + throw std::runtime_error("Not implemented"); +} +MinifiStatus MinifiProcessSessionWrite(MinifiProcessSession*, MinifiFlowFile*, int64_t (*)(void* user_ctx, MinifiOutputStream*), void*) { + throw std::runtime_error("Not implemented"); +} + +void MinifiConfigGet(MinifiExtensionContext*, MinifiStringView, void (*)(void* user_ctx, MinifiStringView config_value), void*) { + throw std::runtime_error("Not implemented"); +} + +size_t MinifiInputStreamSize(MinifiInputStream*) { + throw std::runtime_error("Not implemented"); +} + +int64_t MinifiInputStreamRead(MinifiInputStream*, char*, size_t) { + throw std::runtime_error("Not implemented"); +} +int64_t MinifiOutputStreamWrite(MinifiOutputStream*, const char*, size_t) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiProcessSessionSetFlowFileAttribute(MinifiProcessSession*, MinifiFlowFile*, MinifiStringView, const MinifiStringView*) { + throw std::runtime_error("Not implemented"); +} +MinifiBool MinifiProcessSessionGetFlowFileAttribute(MinifiProcessSession*, MinifiFlowFile*, MinifiStringView, + void (*)(void* user_ctx, MinifiStringView attribute_value), void*) { + throw std::runtime_error("Not implemented"); +} +void MinifiProcessSessionGetFlowFileAttributes(MinifiProcessSession*, MinifiFlowFile*, + void (*)(void* user_ctx, MinifiStringView attribute_name, MinifiStringView attribute_value), void*) { + throw std::runtime_error("Not implemented"); +} +uint64_t MinifiProcessSessionGetFlowFileSize(MinifiProcessSession*, MinifiFlowFile*) { + throw std::runtime_error("Not implemented"); +} +MinifiStatus MinifiProcessSessionGetFlowFileId(MinifiProcessSession*, MinifiFlowFile*, void (*)(void* user_ctx, MinifiStringView flow_file_id), + void*) { + throw std::runtime_error("Not implemented"); +} + +MinifiStatus MinifiControllerServiceContextGetProperty(MinifiControllerServiceContext*, MinifiStringView, + void (*)(void* user_ctx, MinifiStringView property_value), void*) { + throw std::runtime_error("Not implemented"); +} diff --git a/extension-framework/cpp-extension-lib/src/core/ControllerServiceContext.cpp b/extension-framework/cpp-extension-lib/src/core/ControllerServiceContext.cpp index 089112c042..be5104c3b8 100644 --- a/extension-framework/cpp-extension-lib/src/core/ControllerServiceContext.cpp +++ b/extension-framework/cpp-extension-lib/src/core/ControllerServiceContext.cpp @@ -22,7 +22,7 @@ namespace org::apache::nifi::minifi::api::core { std::expected ControllerServiceContext::getProperty(const std::string_view name) const { std::optional value = std::nullopt; - const MinifiStatus status = MinifiControllerServiceContextGetProperty(impl_, utils::toStringView(name), + const MinifiStatus status = MinifiControllerServiceContextGetProperty(impl_, utils::minifiStringView(name), [] (void* data, const MinifiStringView result) { (*static_cast*>(data)) = std::string(result.data, result.length); }, &value); diff --git a/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp b/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp index d260b9c0c9..a4dd9505cd 100644 --- a/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp +++ b/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp @@ -1,5 +1,5 @@ /** -* Licensed to the Apache Software Foundation (ASF) under one or more + * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 @@ -16,34 +16,40 @@ */ #include "api/core/ProcessContext.h" -#include "api/utils/minifi-c-utils.h" + #include "api/core/FlowFile.h" +#include "api/utils/minifi-c-utils.h" namespace org::apache::nifi::minifi::api::core { -std::expected ProcessContext::getProperty(std::string_view name, const FlowFile* flow_file) const { +std::expected CffiProcessContext::getProperty(const minifi::core::PropertyReference& property_reference, + const FlowFile* flow_file) const { + return getProperty(property_reference.name, flow_file); +} + +std::expected CffiProcessContext::getProperty(std::string_view name, const FlowFile* flow_file) const { std::optional value; - MinifiStatus status = MinifiProcessContextGetProperty(impl_, utils::toStringView(name), flow_file ? flow_file->get() : MINIFI_NULL, - [] (void* data, MinifiStringView result) { - (*static_cast*>(data)) = std::string(result.data, result.length); - }, &value); + const MinifiStatus status = MinifiProcessContextGetProperty( + impl_, + utils::minifiStringView(name), + flow_file ? flow_file->get() : MINIFI_NULL, + [](void* data, const MinifiStringView result) { (*static_cast*>(data)) = std::string(result.data, result.length); }, + &value); - if (!value) { - return std::unexpected{utils::make_error_code(status)}; - } + if (!value) { return std::unexpected{utils::make_error_code(status)}; } return value.value(); } -bool ProcessContext::hasNonEmptyProperty(std::string_view name) const { - return MinifiProcessContextHasNonEmptyProperty(impl_, utils::toStringView(name)); +bool CffiProcessContext::hasNonEmptyProperty(std::string_view name) const { + return MinifiProcessContextHasNonEmptyProperty(impl_, utils::minifiStringView(name)); } -std::expected ProcessContext::getControllerService(const std::string_view controller_service_name, - const std::string_view controller_service_class) const { +std::expected CffiProcessContext::getControllerService(const std::string_view name, + const std::string_view type) const { MinifiControllerService* controller_service = nullptr; if (const MinifiStatus status = MinifiProcessContextGetControllerService(impl_, - utils::toStringView(controller_service_name), - utils::toStringView(controller_service_class), + utils::minifiStringView(name), + utils::minifiStringView(type), &controller_service); status != MINIFI_STATUS_SUCCESS) { return std::unexpected{utils::make_error_code(status)}; @@ -51,4 +57,33 @@ std::expected ProcessContext::getCont return controller_service; } +std::map CffiProcessContext::getDynamicProperties(const FlowFile* flow_file) const { + std::map result; + MinifiProcessContextGetDynamicProperties( + impl_, + flow_file ? flow_file->get() : MINIFI_NULL, + [](void* user_ctx, const MinifiStringView key, const MinifiStringView value) { + static_cast*>(user_ctx)->emplace(utils::toString(key), utils::toString(value)); + }, + &result); + return result; +} + +std::expected CffiProcessContext::getSslData(const std::string_view name) const { + auto ssl_data = utils::net::SslData{}; + + if (const auto status = MinifiProcessContextGetSslData(impl_, utils::minifiStringView(name), [](void* data, const MinifiSslData* minifi_ssl_data) { + auto* my_ssl_data = static_cast(data); + my_ssl_data->ca_loc = utils::toString(minifi_ssl_data->ca_certificate_file); + my_ssl_data->cert_loc = utils::toString(minifi_ssl_data->certificate_file); + my_ssl_data->key_loc = utils::toString(minifi_ssl_data->private_key_file); + my_ssl_data->key_pw = utils::toString(minifi_ssl_data->passphrase); + }, &ssl_data); + status != MINIFI_STATUS_SUCCESS) { + return std::unexpected{utils::make_error_code(status)}; + } + + return ssl_data; +} + } // namespace org::apache::nifi::minifi::api::core diff --git a/extension-framework/cpp-extension-lib/src/core/ProcessSession.cpp b/extension-framework/cpp-extension-lib/src/core/ProcessSession.cpp index 8b13b09c2a..5bf12b1d64 100644 --- a/extension-framework/cpp-extension-lib/src/core/ProcessSession.cpp +++ b/extension-framework/cpp-extension-lib/src/core/ProcessSession.cpp @@ -69,28 +69,34 @@ class MinifiInputStreamWrapper : public io::InputStreamImpl { } // namespace -FlowFile ProcessSession::get() { +FlowFile CffiProcessSession::get() { return FlowFile{MinifiProcessSessionGet(impl_)}; } -FlowFile ProcessSession::create(const FlowFile* parent) { +FlowFile CffiProcessSession::create(const FlowFile* parent) { return FlowFile{MinifiProcessSessionCreate(impl_, parent ? parent->get() : MINIFI_NULL)}; } -void ProcessSession::transfer(FlowFile ff, const minifi::core::Relationship& relationship) { +void CffiProcessSession::penalize(FlowFile& ff) { + if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionPenalize(impl_, ff.get())) { + throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to penalize flowfile"); + } +} + +void CffiProcessSession::transfer(FlowFile ff, const minifi::core::Relationship& relationship) { const auto rel_name = relationship.getName(); - if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionTransfer(impl_, ff.release(), utils::toStringView(rel_name))) { + if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionTransfer(impl_, ff.release(), utils::minifiStringView(rel_name))) { throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to transfer flowfile"); } } -void ProcessSession::remove(FlowFile ff) { +void CffiProcessSession::remove(FlowFile ff) { if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionRemove(impl_, ff.release())) { throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to remove flowfile"); } } -void ProcessSession::write(FlowFile& flow_file, const io::OutputStreamCallback& callback) { +void CffiProcessSession::write(FlowFile& flow_file, const io::OutputStreamCallback& callback) { const auto status = MinifiProcessSessionWrite( impl_, flow_file.get(), @@ -103,7 +109,7 @@ void ProcessSession::write(FlowFile& flow_file, const io::OutputStreamCallback& if (status != MINIFI_STATUS_SUCCESS) { throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to process flowfile content"); } } -void ProcessSession::read(FlowFile& flow_file, const io::InputStreamCallback& callback) { +void CffiProcessSession::read(FlowFile& flow_file, const io::InputStreamCallback& callback) { const auto status = MinifiProcessSessionRead( impl_, flow_file.get(), @@ -116,28 +122,28 @@ void ProcessSession::read(FlowFile& flow_file, const io::InputStreamCallback& ca if (status != MINIFI_STATUS_SUCCESS) { throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to process flowfile content"); } } -void ProcessSession::setAttribute(FlowFile& ff, const std::string_view key, std::string value) { // NOLINT(performance-unnecessary-value-param) - const MinifiStringView value_ref = utils::toStringView(value); - if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionSetFlowFileAttribute(impl_, ff.get(), utils::toStringView(key), &value_ref)) { +void CffiProcessSession::setAttribute(FlowFile& ff, const std::string_view key, std::string value) { // NOLINT(performance-unnecessary-value-param) + const MinifiStringView value_ref = utils::minifiStringView(value); + if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionSetFlowFileAttribute(impl_, ff.get(), utils::minifiStringView(key), &value_ref)) { throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to set attribute"); } } -void ProcessSession::removeAttribute(FlowFile& ff, const std::string_view key) { - if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionSetFlowFileAttribute(impl_, ff.get(), utils::toStringView(key), nullptr)) { +void CffiProcessSession::removeAttribute(FlowFile& ff, const std::string_view key) { + if (MINIFI_STATUS_SUCCESS != MinifiProcessSessionSetFlowFileAttribute(impl_, ff.get(), utils::minifiStringView(key), nullptr)) { throw minifi::Exception(minifi::FILE_OPERATION_EXCEPTION, "Failed to remove attribute"); } } -std::optional ProcessSession::getAttribute(FlowFile& ff, std::string_view key) { +std::optional CffiProcessSession::getAttribute(FlowFile& ff, std::string_view key) { std::optional result; - MinifiProcessSessionGetFlowFileAttribute(impl_, ff.get(), utils::toStringView(key), [] (void* user_ctx, MinifiStringView value) { + MinifiProcessSessionGetFlowFileAttribute(impl_, ff.get(), utils::minifiStringView(key), [] (void* user_ctx, MinifiStringView value) { *static_cast*>(user_ctx) = std::string{value.data, value.length}; }, &result); return result; } -std::map ProcessSession::getAttributes(FlowFile& ff) { +std::map CffiProcessSession::getAttributes(const FlowFile& ff) const { std::map result; MinifiProcessSessionGetFlowFileAttributes(impl_, ff.get(), [] (void* user_ctx, const MinifiStringView key, const MinifiStringView value) { static_cast*>(user_ctx)->insert({std::string{key.data, key.length}, std::string{value.data, value.length}}); @@ -145,6 +151,18 @@ std::map ProcessSession::getAttributes(FlowFile& ff) { return result; } +std::string CffiProcessSession::getFlowFileId(const FlowFile& ff) const { + std::string result; + MinifiProcessSessionGetFlowFileId(impl_, ff.get(), [](void* user_ctx, const MinifiStringView value) { + *static_cast(user_ctx) = std::string{value.data, value.length}; + }, &result); + return result; +} + +uint64_t CffiProcessSession::getFlowFileSize(const FlowFile& ff) const { + return MinifiProcessSessionGetFlowFileSize(impl_, ff.get()); +} + void ProcessSession::writeBuffer(FlowFile& flow_file, std::span buffer) { writeBuffer(flow_file, as_bytes(buffer)); } diff --git a/extension-framework/cpp-extension-lib/src/core/logging/Logger.cpp b/extension-framework/cpp-extension-lib/src/core/logging/Logger.cpp index d91a67f609..4f5f2f422e 100644 --- a/extension-framework/cpp-extension-lib/src/core/logging/Logger.cpp +++ b/extension-framework/cpp-extension-lib/src/core/logging/Logger.cpp @@ -49,19 +49,19 @@ minifi::core::logging::LOG_LEVEL toLogLevel(MinifiLogLevel level) { } // namespace -void Logger::set_max_log_size(int size) { +void CffiLogger::set_max_log_size(const int size) { MinifiLoggerSetMaxLogSize(impl_, size); } -void Logger::log_string(minifi::core::logging::LOG_LEVEL level, std::string str) { +void CffiLogger::log_string(const minifi::core::logging::LOG_LEVEL level, const std::string str) { MinifiLoggerLogString(impl_, toCLogLevel(level), MinifiStringView{.data = str.data(), .length = str.length()}); } -bool Logger::should_log(minifi::core::logging::LOG_LEVEL level) { +bool CffiLogger::should_log(const minifi::core::logging::LOG_LEVEL level) { return MinifiLoggerShouldLog(impl_, toCLogLevel(level)); } -[[nodiscard]] minifi::core::logging::LOG_LEVEL Logger::level() const { +[[nodiscard]] minifi::core::logging::LOG_LEVEL CffiLogger::level() const { return toLogLevel(MinifiLoggerLevel(impl_)); } diff --git a/extensions/llamacpp/processors/ExtensionInitializer.cpp b/extensions/llamacpp/processors/ExtensionInitializer.cpp index 85d610a7d9..8e06bf0cc3 100644 --- a/extensions/llamacpp/processors/ExtensionInitializer.cpp +++ b/extensions/llamacpp/processors/ExtensionInitializer.cpp @@ -28,8 +28,8 @@ CEXTENSIONAPI const uint32_t MinifiApiVersion = MINIFI_API_VERSION; CEXTENSIONAPI void MinifiInitExtension(MinifiExtensionContext* extension_context) { MinifiExtensionDefinition extension_definition{ - .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)), - .version = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_VERSION)), + .name = minifi::api::utils::minifiStringView(MAKESTRING(EXTENSION_NAME)), + .version = minifi::api::utils::minifiStringView(MAKESTRING(EXTENSION_VERSION)), .deinit = nullptr, .user_data = nullptr }; diff --git a/extensions/llamacpp/processors/RunLlamaCppInference.cpp b/extensions/llamacpp/processors/RunLlamaCppInference.cpp index 5927a0199e..a8d587521c 100644 --- a/extensions/llamacpp/processors/RunLlamaCppInference.cpp +++ b/extensions/llamacpp/processors/RunLlamaCppInference.cpp @@ -31,7 +31,7 @@ namespace org::apache::nifi::minifi::extensions::llamacpp::processors { MinifiStatus RunLlamaCppInference::onScheduleImpl(api::core::ProcessContext& context) { model_path_.clear(); model_path_ = api::utils::parseProperty(context, ModelPath); - system_prompt_ = context.getProperty(SystemPrompt).value_or(""); + system_prompt_ = context.getProperty(SystemPrompt, nullptr).value_or(""); LlamaSamplerParams llama_sampler_params; llama_sampler_params.temperature = api::utils::parseOptionalFloatProperty(context, Temperature); diff --git a/libminifi/test/integration/extension-verification-test/CApiExtension.cpp b/libminifi/test/integration/extension-verification-test/CApiExtension.cpp index 546a229056..13bec7e0c6 100644 --- a/libminifi/test/integration/extension-verification-test/CApiExtension.cpp +++ b/libminifi/test/integration/extension-verification-test/CApiExtension.cpp @@ -44,8 +44,8 @@ CEXTENSIONAPI const uint32_t MinifiApiVersion = MINIFI_TEST_API_VERSION; CEXTENSIONAPI void MinifiInitExtension(MinifiExtensionContext* extension_context) { MinifiExtensionDefinition extension_definition{ - .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)), - .version = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_VERSION)), + .name = minifi::api::utils::minifiStringView(MAKESTRING(EXTENSION_NAME)), + .version = minifi::api::utils::minifiStringView(MAKESTRING(EXTENSION_VERSION)), .deinit = nullptr, .user_data = nullptr }; From b2cd0aa67dbbc0ec574a0ed7bd6f971c9299a68b Mon Sep 17 00:00:00 2001 From: Martin Zink Date: Tue, 5 May 2026 16:47:50 +0200 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../cpp-extension-lib/mocklib/include/MockLogger.h | 2 +- .../cpp-extension-lib/mocklib/include/MockProcessSession.h | 4 ++-- .../cpp-extension-lib/mocklib/include/MockStreams.h | 1 + .../cpp-extension-lib/mocklib/src/mock-minifi-c.cpp | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h b/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h index 56be27b966..2c54cc6635 100644 --- a/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockLogger.h @@ -27,7 +27,7 @@ class MockLogger : public core::logging::Logger { public: void set_max_log_size(int) override {} void log_string(const core::logging::LOG_LEVEL level, std::string s) override { logs_[level].emplace_back(std::move(s)); } - [[nodiscard]] bool should_log(const core::logging::LOG_LEVEL level) override { return level > log_level_; } + [[nodiscard]] bool should_log(const core::logging::LOG_LEVEL level) override { return level >= log_level_; } [[nodiscard]] core::logging::LOG_LEVEL level() const override { return log_level_; } core::logging::LOG_LEVEL log_level_ = core::logging::LOG_LEVEL::trace; diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h index fa53671a9c..51844d3bd6 100644 --- a/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessSession.h @@ -51,8 +51,8 @@ class MockProcessSession : public api::core::ProcessSession { MockProcessSession() = default; MockProcessSession(const MockProcessSession&) = delete; MockProcessSession& operator=(const MockProcessSession&) = delete; - MockProcessSession(const MockProcessSession&&) = delete; - MockProcessSession& operator=(const MockProcessSession&&) = delete; + MockProcessSession(MockProcessSession&&) = delete; + MockProcessSession& operator=(MockProcessSession&&) = delete; ~MockProcessSession() override; diff --git a/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h b/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h index 73352daf74..b5204c58c6 100644 --- a/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h +++ b/extension-framework/cpp-extension-lib/mocklib/include/MockStreams.h @@ -19,6 +19,7 @@ #include #include +#include #include #include diff --git a/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp b/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp index 8b48d0d578..a546f07ad3 100644 --- a/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp +++ b/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp @@ -46,13 +46,13 @@ MinifiBool MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext*, Minifi MinifiStatus MinifiProcessContextGetControllerService(MinifiProcessContext*, MinifiStringView, MinifiStringView, MinifiControllerService**) { throw std::runtime_error("Not implemented"); } -void MinifiProcessContextGetDynamicProperties(MinifiProcessContext*, +void MinifiProcessContextGetDynamicProperties(MinifiProcessContext*, MinifiFlowFile*, void (*)(void* user_ctx, MinifiStringView dynamic_property_name, MinifiStringView dynamic_property_value), void*) { throw std::runtime_error("Not implemented"); } MinifiStatus MinifiProcessContextGetSslData(MinifiProcessContext*, MinifiStringView, - void (*)(void* user_ctx, const MinifiSslData& ssl_data), void*) { + void (*)(void* user_ctx, const MinifiSslData* ssl_data), void*) { throw std::runtime_error("Not implemented"); } From b89c26e772f1b01d1f26df8e572517eba69c3766 Mon Sep 17 00:00:00 2001 From: Martin Zink Date: Tue, 5 May 2026 18:15:50 +0200 Subject: [PATCH 3/3] typedef MinifiSslData --- minifi-api/include/minifi-c/minifi-c.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/minifi-api/include/minifi-c/minifi-c.h b/minifi-api/include/minifi-c/minifi-c.h index 1345a01b70..9eb707f355 100644 --- a/minifi-api/include/minifi-c/minifi-c.h +++ b/minifi-api/include/minifi-c/minifi-c.h @@ -272,13 +272,13 @@ MinifiStatus MinifiControllerServiceContextGetProperty(MinifiControllerServiceCo void(*cb)(void* user_ctx, MinifiStringView property_value), void* user_ctx); -struct MinifiSslData { +typedef struct MinifiSslData { uint8_t version; MinifiStringView ca_certificate_file; MinifiStringView certificate_file; MinifiStringView private_key_file; MinifiStringView passphrase; -}; +} MinifiSslData; MinifiStatus MinifiProcessContextGetSslData(MinifiProcessContext* process_context, MinifiStringView controller_service_name, void (*cb)(void* user_ctx, const MinifiSslData* ssl_data), void* user_ctx);