You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2026/03/30 12:43:34 UTC
(nifi-minifi-cpp) 06/18: MINIFICPP-2715 - Add extension loading tests for version verification
This is an automated email from the ASF dual-hosted git repository.
martinzink pushed a commit to branch controller_c_api_requirements
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit 6bec1d8df90d7155341850a639f0c24e9e8c4bf9
Author: Adam Debreceni <ad...@apache.org>
AuthorDate: Mon Mar 2 14:03:04 2026 +0100
MINIFICPP-2715 - Add extension loading tests for version verification
---
Extensions.md | 2 +-
cmake/Extensions.cmake | 3 +-
extensions/python/pythonloader/PyProcLoader.cpp | 2 +-
libminifi/include/core/extension/ApiVersion.h | 37 +++++++++
libminifi/include/core/extension/Extension.h | 11 +--
libminifi/src/core/extension/ApiVersion.cpp | 33 ++++++++
libminifi/src/core/extension/Extension.cpp | 20 ++---
libminifi/test/integration/CMakeLists.txt | 2 +
.../extension-verification-test/CApiExtension.cpp | 39 ++++++++++
.../extension-verification-test/CMakeLists.txt | 79 +++++++++++++++++++
.../CppApiExtension.cpp | 34 +++-----
.../ExtensionVerificationTests.cpp | 90 ++++++++++++++++++++++
.../InvalidMissingInitExtension.cpp | 17 ++++
.../extension-verification-test/dummy-cpp-api.def | 3 +
14 files changed, 326 insertions(+), 46 deletions(-)
diff --git a/Extensions.md b/Extensions.md
index 0bfbd5bd9..159232f9a 100644
--- a/Extensions.md
+++ b/Extensions.md
@@ -82,7 +82,7 @@ extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
.processors_count = 0,
.processors_ptr = nullptr
};
- return MinifiCreateCppExtension(&ext_create_info);
+ return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
}
```
diff --git a/cmake/Extensions.cmake b/cmake/Extensions.cmake
index 6ea93f1cb..6e25d288b 100644
--- a/cmake/Extensions.cmake
+++ b/cmake/Extensions.cmake
@@ -31,8 +31,7 @@ macro(register_extension extension-name extension-display-name extension-guard d
target_sources(${extension-name} PRIVATE ${CMAKE_SOURCE_DIR}/extensions/ExtensionInitializer.cpp)
endif()
target_compile_definitions(${extension-name}
- PRIVATE "MODULE_NAME=${extension-name}"
- PRIVATE "BUILD_ID_VARIABLE_NAME=${build-id-variable-name}")
+ PRIVATE "MODULE_NAME=${extension-name}")
set_target_properties(${extension-name} PROPERTIES
ENABLE_EXPORTS True
POSITION_INDEPENDENT_CODE ON)
diff --git a/extensions/python/pythonloader/PyProcLoader.cpp b/extensions/python/pythonloader/PyProcLoader.cpp
index cd9cbb998..d4edf9cf2 100644
--- a/extensions/python/pythonloader/PyProcLoader.cpp
+++ b/extensions/python/pythonloader/PyProcLoader.cpp
@@ -49,5 +49,5 @@ extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* config) {
.processors_count = 0,
.processors_ptr = nullptr
};
- return minifi::utils::MinifiCreateCppExtension( &ext_create_info);
+ return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
}
diff --git a/libminifi/include/core/extension/ApiVersion.h b/libminifi/include/core/extension/ApiVersion.h
new file mode 100644
index 000000000..01acb82cb
--- /dev/null
+++ b/libminifi/include/core/extension/ApiVersion.h
@@ -0,0 +1,37 @@
+/**
+* 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 <string>
+
+namespace org::apache::nifi::minifi::core::extension {
+
+struct ApiVersion {
+ int major;
+ int minor;
+ int patch;
+
+ std::string str() const {
+ return std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch);
+ }
+};
+
+ApiVersion getAgentApiVersion();
+void setAgentApiVersion(ApiVersion api_version);
+
+} // namespace org::apache::nifi::minifi::core::extension
diff --git a/libminifi/include/core/extension/Extension.h b/libminifi/include/core/extension/Extension.h
index 2a71a6fbc..356efed4c 100644
--- a/libminifi/include/core/extension/Extension.h
+++ b/libminifi/include/core/extension/Extension.h
@@ -25,6 +25,7 @@
#include "minifi-c/minifi-c.h"
#include "minifi-cpp/core/logging/Logger.h"
#include "minifi-cpp/properties/Configure.h"
+#include "ApiVersion.h"
namespace org::apache::nifi::minifi::core::extension {
@@ -39,12 +40,6 @@ class Extension {
void* user_data;
};
- struct Version {
- int major{MINIFI_API_MAJOR_VERSION};
- int minor{MINIFI_API_MINOR_VERSION};
- int patch{MINIFI_API_PATCH_VERSION};
- };
-
Extension(std::string name, std::filesystem::path library_path);
Extension(const Extension&) = delete;
@@ -56,7 +51,7 @@ class Extension {
bool initialize(const std::shared_ptr<minifi::Configure>& configure);
- Version version() const {return version_;}
+ [[nodiscard]] ApiVersion apiVersion() const {return api_version_;}
private:
#ifdef WIN32
@@ -80,7 +75,7 @@ class Extension {
std::filesystem::path library_path_;
gsl::owner<void*> handle_ = nullptr;
- Version version_{};
+ ApiVersion api_version_;
std::unique_ptr<Info> info_;
const std::shared_ptr<logging::Logger> logger_;
diff --git a/libminifi/src/core/extension/ApiVersion.cpp b/libminifi/src/core/extension/ApiVersion.cpp
new file mode 100644
index 000000000..1f515b25b
--- /dev/null
+++ b/libminifi/src/core/extension/ApiVersion.cpp
@@ -0,0 +1,33 @@
+/**
+* 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 "core/extension/ApiVersion.h"
+#include "minifi-c/minifi-c.h"
+
+namespace org::apache::nifi::minifi::core::extension {
+
+static ApiVersion agent_api_version{.major = MINIFI_API_MAJOR_VERSION, .minor = MINIFI_API_MINOR_VERSION, .patch = MINIFI_API_PATCH_VERSION};
+
+ApiVersion getAgentApiVersion() {
+ return agent_api_version;
+}
+
+void setAgentApiVersion(ApiVersion api_version) {
+ agent_api_version = api_version;
+}
+
+} // namespace org::apache::nifi::minifi::core::extension
\ No newline at end of file
diff --git a/libminifi/src/core/extension/Extension.cpp b/libminifi/src/core/extension/Extension.cpp
index 35d0634b9..9073b6c9a 100644
--- a/libminifi/src/core/extension/Extension.cpp
+++ b/libminifi/src/core/extension/Extension.cpp
@@ -45,6 +45,7 @@ namespace org::apache::nifi::minifi::core::extension {
Extension::Extension(std::string name, std::filesystem::path library_path)
: name_(std::move(name)),
library_path_(std::move(library_path)),
+ api_version_(getAgentApiVersion()),
logger_(logging::LoggerFactory<Extension>::getLogger()) {
}
@@ -65,7 +66,7 @@ bool Extension::load(bool global) {
return true;
}
if (!findSymbol("MinifiInitExtension")) {
- logger_->log_error("Failed to load c extension '{}' at '{}': No initializer found", name_, library_path_);
+ logger_->log_error("Failed to load as c extension '{}' at '{}': No initializer found", name_, library_path_);
return false;
}
auto api_version = reinterpret_cast<const char* const*>(findSymbol("MinifiApiVersion"));
@@ -79,21 +80,21 @@ bool Extension::load(bool global) {
return false;
}
gsl_Assert(match.size() == 4);
- version_.major = std::stoi(match[1]);
- version_.minor = std::stoi(match[2]);
- version_.patch = std::stoi(match[3]);
- if (version_.major != MINIFI_API_MAJOR_VERSION) {
+ api_version_.major = std::stoi(match[1]);
+ api_version_.minor = std::stoi(match[2]);
+ api_version_.patch = std::stoi(match[3]);
+ if (api_version_.major != getAgentApiVersion().major) {
logger_->log_error("Failed to load c extension '{}' at '{}': Api major version mismatch, application is '{}' while extension is '{}'",
- name_, library_path_, MINIFI_API_VERSION, *api_version);
+ name_, library_path_, getAgentApiVersion().str(), *api_version);
return false;
}
- if (version_.minor > MINIFI_API_MINOR_VERSION) {
+ if (api_version_.minor > getAgentApiVersion().minor) {
logger_->log_error("Failed to load c extension '{}' at '{}': Extension is built for a newer version, application is '{}' while extension is '{}'",
- name_, library_path_, MINIFI_API_VERSION, *api_version);
+ name_, library_path_, getAgentApiVersion().str(), *api_version);
return false;
}
logger_->log_debug("Loaded c extension '{}' at '{}': Application version is '{}', extension version is '{}'",
- name_, library_path_, MINIFI_API_VERSION, *api_version);
+ name_, library_path_, getAgentApiVersion().str(), *api_version);
return true;
}
@@ -163,6 +164,7 @@ bool Extension::initialize(const std::shared_ptr<minifi::Configure>& configure)
logger_->log_error("Failed to initialize extension '{}'", name_);
return false;
}
+ logger_->log_debug("Initialized extension '{}'", name_);
return true;
}
diff --git a/libminifi/test/integration/CMakeLists.txt b/libminifi/test/integration/CMakeLists.txt
index 3fb3fd88a..44e98f76a 100644
--- a/libminifi/test/integration/CMakeLists.txt
+++ b/libminifi/test/integration/CMakeLists.txt
@@ -45,3 +45,5 @@ ENDFOREACH()
target_link_libraries(OnScheduleErrorHandlingTests minifi-test-processors)
message("-- Finished building ${INT_TEST_COUNT} integration test file(s)...")
+
+add_subdirectory(extension-verification-test)
diff --git a/libminifi/test/integration/extension-verification-test/CApiExtension.cpp b/libminifi/test/integration/extension-verification-test/CApiExtension.cpp
new file mode 100644
index 000000000..e6fd7cfbc
--- /dev/null
+++ b/libminifi/test/integration/extension-verification-test/CApiExtension.cpp
@@ -0,0 +1,39 @@
+/**
+*
+ * 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 "api/core/Resource.h"
+#include "api/utils/minifi-c-utils.h"
+
+#define MKSOC(x) #x
+#define MAKESTRING(x) MKSOC(x) // NOLINT(cppcoreguidelines-macro-usage)
+
+namespace minifi = org::apache::nifi::minifi;
+
+extern "C" const char* const MinifiApiVersion = MINIFI_TEST_API_VERSION;
+
+extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+ MinifiExtensionCreateInfo ext_create_info{
+ .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)),
+ .version = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_VERSION)),
+ .deinit = nullptr,
+ .user_data = nullptr,
+ .processors_count = 0,
+ .processors_ptr = nullptr,
+ };
+ return MinifiCreateExtension(&ext_create_info);
+}
\ No newline at end of file
diff --git a/libminifi/test/integration/extension-verification-test/CMakeLists.txt b/libminifi/test/integration/extension-verification-test/CMakeLists.txt
new file mode 100644
index 000000000..32c068106
--- /dev/null
+++ b/libminifi/test/integration/extension-verification-test/CMakeLists.txt
@@ -0,0 +1,79 @@
+# 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.
+#
+
+add_minifi_executable(ExtensionVerificationTests ExtensionVerificationTests.cpp)
+createIntegrationTests(ExtensionVerificationTests)
+target_link_libraries(${testfilename} core-minifi Catch2WithMain Threads::Threads)
+add_test(NAME ExtensionVerificationTests COMMAND ExtensionVerificationTests)
+
+function(create_loading_test_extension extension-name extension-main)
+ add_library(${extension-name} SHARED ${extension-main})
+ add_dependencies(ExtensionVerificationTests ${extension-name})
+ target_compile_definitions(${extension-name} PRIVATE MODULE_NAME=${extension-name})
+ set_target_properties(${extension-name} PROPERTIES ENABLE_EXPORTS True POSITION_INDEPENDENT_CODE ON)
+ if(WIN32)
+ set_target_properties(${extension-name} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+ WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
+ else()
+ set_target_properties(${extension-name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+ endif()
+endfunction()
+
+function(create_c_test_extension extension-name custom_api_version)
+ set(extension-name "test-extension-loading-${extension-name}")
+ create_loading_test_extension(${extension-name} CApiExtension.cpp)
+ target_link_libraries(${extension-name} minifi-cpp-extension-lib)
+ target_compile_definitions(${extension-name} PRIVATE MINIFI_TEST_API_VERSION="${custom_api_version}")
+ target_compile_definitions(${extension-name}
+ PRIVATE "EXTENSION_NAME=${extension-name}" "EXTENSION_VERSION=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+endfunction()
+
+add_library(dummy-core-minifi INTERFACE)
+target_include_directories(dummy-core-minifi INTERFACE $<TARGET_PROPERTY:minifi-extension-framework,INTERFACE_INCLUDE_DIRECTORIES>)
+if (WIN32)
+ set(DUMMY_IMPORT_LIB_FILE ${CMAKE_CURRENT_BINARY_DIR}/dummy-cpp-api.lib)
+ add_custom_target(dummy_cpp_api_import_lib
+ COMMAND lib.exe /def:${CMAKE_CURRENT_SOURCE_DIR}/dummy-cpp-api.def /out:${IMPORT_LIB_FILE} /machine:x64
+ BYPRODUCTS ${IMPORT_LIB_FILE}
+ )
+
+ add_dependencies(dummy-core-minifi dummy_cpp_api_import_lib)
+ target_link_libraries(dummy-core-minifi INTERFACE ${IMPORT_LIB_FILE})
+elseif (APPLE)
+ target_link_options(dummy-core-minifi INTERFACE -undefined dynamic_lookup)
+endif()
+
+create_loading_test_extension(test-extension-loading-invalid-build-id-cpp CppApiExtension.cpp)
+target_link_libraries(test-extension-loading-invalid-build-id-cpp dummy-core-minifi)
+target_compile_definitions(test-extension-loading-invalid-build-id-cpp PRIVATE MINIFI_CREATE_EXTENSION_FN=MinifiCreateCppExtension_NonMatchingBuildId)
+
+create_loading_test_extension(test-extension-loading-valid-build-id-cpp CppApiExtension.cpp)
+target_link_libraries(test-extension-loading-valid-build-id-cpp dummy-core-minifi)
+target_compile_definitions(test-extension-loading-valid-build-id-cpp PRIVATE MINIFI_CREATE_EXTENSION_FN=MinifiCreateCppExtension_${BUILD_IDENTIFIER})
+
+create_c_test_extension(same-version "1.1.1")
+create_c_test_extension(greater-major-version "2.0.0")
+create_c_test_extension(smaller-major-version "0.1.0")
+create_c_test_extension(greater-minor-version "1.2.0")
+create_c_test_extension(smaller-minor-version "1.0.1")
+create_c_test_extension(greater-patch-version "1.1.2")
+create_c_test_extension(smaller-patch-version "1.1.0")
+create_loading_test_extension(test-extension-loading-missing-init InvalidMissingInitExtension.cpp)
diff --git a/extensions/python/pythonloader/PyProcLoader.cpp b/libminifi/test/integration/extension-verification-test/CppApiExtension.cpp
similarity index 53%
copy from extensions/python/pythonloader/PyProcLoader.cpp
copy to libminifi/test/integration/extension-verification-test/CppApiExtension.cpp
index cd9cbb998..0503a8c17 100644
--- a/extensions/python/pythonloader/PyProcLoader.cpp
+++ b/libminifi/test/integration/extension-verification-test/CppApiExtension.cpp
@@ -1,5 +1,5 @@
/**
- *
+*
* 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.
@@ -15,39 +15,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "minifi-c/minifi-c.h"
-#include "utils/ExtensionInitUtils.h"
-#include "PythonCreator.h"
-#include "minifi-cpp/agent/agent_version.h"
-#include "PythonBindings.h"
-#include "core/Resource.h"
-namespace minifi = org::apache::nifi::minifi;
+#include <string_view>
+#include "utils/ExtensionInitUtils.h"
-static minifi::extensions::python::PythonCreator& getPythonCreator() {
- static minifi::extensions::python::PythonCreator instance("PythonCreator");
- return instance;
-}
+#define MKSOC(x) #x
+#define MAKESTRING(x) MKSOC(x) // NOLINT(cppcoreguidelines-macro-usage)
-// request this module (shared library) to be opened into the global namespace, exposing
-// the symbols of the python library
-extern "C" const int LOAD_MODULE_AS_GLOBAL = 1;
+namespace minifi = org::apache::nifi::minifi;
-extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* config) {
- getPythonCreator().configure([&] (std::string_view key) -> std::optional<std::string> {
- std::optional<std::string> result;
- MinifiConfigGet(config, minifi::utils::toStringView(key), [] (void* user_data, MinifiStringView value) {
- *static_cast<std::optional<std::string>*>(user_data) = std::string{value.data, value.length};
- }, &result);
- return result;
- });
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
MinifiExtensionCreateInfo ext_create_info{
.name = minifi::utils::toStringView(MAKESTRING(MODULE_NAME)),
- .version = minifi::utils::toStringView(minifi::AgentBuild::VERSION),
+ .version = minifi::utils::toStringView("1.0.0"),
.deinit = nullptr,
.user_data = nullptr,
.processors_count = 0,
.processors_ptr = nullptr
};
- return minifi::utils::MinifiCreateCppExtension( &ext_create_info);
+ return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
}
diff --git a/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp b/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp
new file mode 100644
index 000000000..6fa304691
--- /dev/null
+++ b/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp
@@ -0,0 +1,90 @@
+/**
+*
+ * 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.
+ */
+
+#define CUSTOM_EXTENSION_INIT
+
+#include "unit/TestBase.h"
+#include "unit/Catch.h"
+#include "unit/TestUtils.h"
+#include "core/extension/ExtensionManager.h"
+#include "core/extension/ApiVersion.h"
+
+namespace minifi = org::apache::nifi::minifi;
+
+class ExtensionLoadingTestController {
+ public:
+ ExtensionLoadingTestController(std::string pattern): extension_manager_{[&] () {
+ LogTestController::getInstance().clear();
+ LogTestController::getInstance().setTrace<core::extension::ExtensionManager>();
+ LogTestController::getInstance().setTrace<core::extension::Extension>();
+ minifi::core::extension::setAgentApiVersion({.major = 1, .minor = 1, .patch = 1});
+ auto config = minifi::Configure::create();
+ config->set(minifi::Configuration::nifi_extension_path, pattern);
+ return config;
+ }()} {}
+
+ core::extension::ExtensionManager extension_manager_;
+};
+
+TEST_CASE("Can load cpp-api extensions with same build id") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-valid-build-id-cpp*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded cpp extension 'test-extension-loading-valid-build-id-cpp'"));
+}
+
+TEST_CASE("Can load c-api extensions with same version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-same-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c extension 'test-extension-loading-same-version'"));
+}
+
+TEST_CASE("Can't load cpp-api extensions with different build id") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-invalid-build-id-cpp*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to load extension 'test-extension-loading-invalid-build-id-cpp'"));
+}
+
+TEST_CASE("Can't load c-api extensions with greater major version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-greater-major-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to load c extension 'test-extension-loading-greater-major-version'"));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Api major version mismatch, application is '1.1.1' while extension is '2.0.0'"));
+}
+
+TEST_CASE("Can't load c-api extensions with smaller major version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-smaller-major-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to load c extension 'test-extension-loading-smaller-major-version'"));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Api major version mismatch, application is '1.1.1' while extension is '0.1.0'"));
+}
+
+TEST_CASE("Can't load c-api extensions with greater minor version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-greater-minor-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to load c extension 'test-extension-loading-greater-minor-version'"));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Extension is built for a newer version"));
+}
+
+TEST_CASE("Can load c-api extensions with smaller minor version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-smaller-minor-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c extension 'test-extension-loading-smaller-minor-version'"));
+}
+
+TEST_CASE("Can load c-api extensions with greater patch version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-greater-patch-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c extension 'test-extension-loading-greater-patch-version'"));
+}
+
+TEST_CASE("Can load c-api extensions with smaller patch version") {
+ ExtensionLoadingTestController controller{"*test-extension-loading-smaller-patch-version*"};
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c extension 'test-extension-loading-smaller-patch-version'"));
+}
diff --git a/libminifi/test/integration/extension-verification-test/InvalidMissingInitExtension.cpp b/libminifi/test/integration/extension-verification-test/InvalidMissingInitExtension.cpp
new file mode 100644
index 000000000..3fbb5023e
--- /dev/null
+++ b/libminifi/test/integration/extension-verification-test/InvalidMissingInitExtension.cpp
@@ -0,0 +1,17 @@
+/**
+*
+ * 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.
+ */
\ No newline at end of file
diff --git a/libminifi/test/integration/extension-verification-test/dummy-cpp-api.def b/libminifi/test/integration/extension-verification-test/dummy-cpp-api.def
new file mode 100644
index 000000000..8da19c75e
--- /dev/null
+++ b/libminifi/test/integration/extension-verification-test/dummy-cpp-api.def
@@ -0,0 +1,3 @@
+LIBRARY core-minifi.dll
+EXPORTS
+ MinifiCreateCppExtension_NonMatchingBuildId