From 0d45bce9ed1edc67bd69d3fe78c2d058b0d9ce26 Mon Sep 17 00:00:00 2001 From: Anton Vinogradov Date: Tue, 14 Jul 2026 20:22:42 +0300 Subject: [PATCH 1/2] IGNITE-28894 C++: add nested thin-client modules to the dev-mode classpath --- modules/platforms/cpp/core/src/jni/os/linux/utils.cpp | 4 ++++ modules/platforms/cpp/core/src/jni/os/win/utils.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/modules/platforms/cpp/core/src/jni/os/linux/utils.cpp b/modules/platforms/cpp/core/src/jni/os/linux/utils.cpp index a40f820303f00..e0ec8681a287e 100644 --- a/modules/platforms/cpp/core/src/jni/os/linux/utils.cpp +++ b/modules/platforms/cpp/core/src/jni/os/linux/utils.cpp @@ -285,6 +285,10 @@ namespace ignite std::string binaryPath = home + "/modules/binary"; std::string binaryCp = ClasspathExploded(binaryPath, true); res.append(binaryCp); + + std::string thinClientPath = home + "/modules/thin-client"; + std::string thinClientCp = ClasspathExploded(thinClientPath, true); + res.append(thinClientCp); } // 2. Add regular jars from "libs" folder excluding "optional". diff --git a/modules/platforms/cpp/core/src/jni/os/win/utils.cpp b/modules/platforms/cpp/core/src/jni/os/win/utils.cpp index a3cf06fa6ffcf..57c975b5c6d31 100644 --- a/modules/platforms/cpp/core/src/jni/os/win/utils.cpp +++ b/modules/platforms/cpp/core/src/jni/os/win/utils.cpp @@ -258,6 +258,10 @@ namespace ignite std::string binaryPath = home + "\\modules\\binary"; std::string binaryCp = ClasspathExploded(binaryPath, true); res.append(binaryCp); + + std::string thinClientPath = home + "\\modules\\thin-client"; + std::string thinClientCp = ClasspathExploded(thinClientPath, true); + res.append(thinClientCp); } // 2. Add regular jars from "libs" folder excluding "optional". From 74211b049ecb4c4adb309a1d6c9a2cdb736f3878 Mon Sep 17 00:00:00 2001 From: Anton Vinogradov Date: Tue, 14 Jul 2026 20:34:20 +0300 Subject: [PATCH 2/2] IGNITE-28894 C++: cover nested modules on the dev-mode classpath with a test --- .../platforms/cpp/core-test/CMakeLists.txt | 3 +- .../cpp/core-test/src/classpath_test.cpp | 89 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 modules/platforms/cpp/core-test/src/classpath_test.cpp diff --git a/modules/platforms/cpp/core-test/CMakeLists.txt b/modules/platforms/cpp/core-test/CMakeLists.txt index 658ad8df0f911..9fbdece2f61b2 100644 --- a/modules/platforms/cpp/core-test/CMakeLists.txt +++ b/modules/platforms/cpp/core-test/CMakeLists.txt @@ -64,7 +64,8 @@ set(SOURCES src/cluster_node_test.cpp src/affinity_test.cpp src/cache_query_schema_test.cpp - src/cluster_group_test.cpp) + src/cluster_group_test.cpp + src/classpath_test.cpp) add_executable(${TARGET} ${SOURCES}) diff --git a/modules/platforms/cpp/core-test/src/classpath_test.cpp b/modules/platforms/cpp/core-test/src/classpath_test.cpp new file mode 100644 index 0000000000000..66192da6030f0 --- /dev/null +++ b/modules/platforms/cpp/core-test/src/classpath_test.cpp @@ -0,0 +1,89 @@ +/* + * 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 + +#include "ignite/jni/utils.h" + +using namespace ignite::jni; + +namespace +{ +#ifdef _WIN32 + const char PATH_SEP = '\\'; +#else + const char PATH_SEP = '/'; +#endif + + /** + * Path to the compiled classes of a nested module, in the form the classpath builder produces. + * + * @param home Ignite home. + * @param group Grouping directory under "modules", e.g. "thin-client". + * @param module Nested module, e.g. "api". + * @return Path to the module classes. + */ + std::string NestedModuleClasses(const std::string& home, const std::string& group, const std::string& module) + { + std::string res(home); + + res += PATH_SEP; res += "modules"; + res += PATH_SEP; res += group; + res += PATH_SEP; res += module; + res += PATH_SEP; res += "target"; + res += PATH_SEP; res += "classes"; + + return res; + } + + /** + * Check that the given path is a part of the classpath. + * + * @param classpath Classpath. + * @param path Path. + */ + void CheckOnClasspath(const std::string& classpath, const std::string& path) + { + BOOST_CHECK_MESSAGE(classpath.find(path) != std::string::npos, path + " is missing from the classpath"); + } +} + +BOOST_AUTO_TEST_SUITE(ClasspathTestSuite) + +/** + * Nested maven modules sit one level deeper than the "modules" scan reaches, so every grouping directory + * needs its own recursive pass. Missing classes are only discovered once a lazily resolved reference is + * hit: ignite-core reaches the thin client from Ignition.startClient() and from management commands, so a + * node starts up just fine without them. + */ +BOOST_AUTO_TEST_CASE(TestNestedModulesOnDevClasspath) +{ + std::string home = ResolveIgniteHome(); + + BOOST_REQUIRE(!home.empty()); + + std::string classpath = CreateIgniteHomeClasspath(home, true); + + CheckOnClasspath(classpath, NestedModuleClasses(home, "binary", "api")); + CheckOnClasspath(classpath, NestedModuleClasses(home, "binary", "impl")); + CheckOnClasspath(classpath, NestedModuleClasses(home, "thin-client", "api")); + CheckOnClasspath(classpath, NestedModuleClasses(home, "thin-client", "impl")); +} + +BOOST_AUTO_TEST_SUITE_END()