You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2022/09/09 20:00:50 UTC

[ignite-3] 09/17: IGNITE-17424 Re-factoring

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

isapego pushed a commit to branch ignite-17424
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit 4ca5c36ef09aff87b2b676e8ea14a267b473b3cd
Author: Igor Sapego <is...@apache.org>
AuthorDate: Tue Aug 30 17:14:32 2022 +0400

    IGNITE-17424 Re-factoring
---
 modules/platforms/cpp/client-test/src/main.cpp     |   3 +
 .../cpp/client/include/ignite/ignite_client.h      |  38 +++++
 modules/platforms/cpp/client/src/ignite_client.cpp |  23 +++
 modules/platforms/cpp/common/Platform.h            |  12 +-
 modules/platforms/cpp/test-common/CMakeLists.txt   |   3 +-
 .../cpp/test-common/include/ignite_node.h          |  80 +++++-----
 .../platforms/cpp/test-common/include/process.h    |  76 ++++-----
 .../platforms/cpp/test-common/include/test_utils.h |  34 ++--
 .../platforms/cpp/test-common/src/ignite_node.cpp  |  77 ++++-----
 modules/platforms/cpp/test-common/src/process.cpp  | 160 ++-----------------
 .../platforms/cpp/test-common/src/test_utils.cpp   | 112 ++++++-------
 .../cpp/test-common/src/win/win_process.h          | 173 +++++++++++++++++++++
 12 files changed, 461 insertions(+), 330 deletions(-)

diff --git a/modules/platforms/cpp/client-test/src/main.cpp b/modules/platforms/cpp/client-test/src/main.cpp
index 1f8eeae3d6..50dcdff9da 100644
--- a/modules/platforms/cpp/client-test/src/main.cpp
+++ b/modules/platforms/cpp/client-test/src/main.cpp
@@ -21,6 +21,9 @@
 
 #include "ignite_node.h"
 
+/**
+ * Run prior to any other tests.
+ */
 void BeforeAll()
 {
     ignite::IgniteNode node;
diff --git a/modules/platforms/cpp/client/include/ignite/ignite_client.h b/modules/platforms/cpp/client/include/ignite/ignite_client.h
index e69de29bb2..03dbfe0ce3 100644
--- a/modules/platforms/cpp/client/include/ignite/ignite_client.h
+++ b/modules/platforms/cpp/client/include/ignite/ignite_client.h
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+namespace ignite
+{
+
+/**
+ * Ignite client.
+ */
+class IgniteClient
+{
+public:
+    IgniteClient() = delete;
+    IgniteClient(IgniteClient&) = delete;
+    IgniteClient& operator=(IgniteClient&) = delete;
+
+
+
+private:
+};
+
+} // namespace ignite
\ No newline at end of file
diff --git a/modules/platforms/cpp/client/src/ignite_client.cpp b/modules/platforms/cpp/client/src/ignite_client.cpp
index e69de29bb2..bcc60eb2c1 100644
--- a/modules/platforms/cpp/client/src/ignite_client.cpp
+++ b/modules/platforms/cpp/client/src/ignite_client.cpp
@@ -0,0 +1,23 @@
+/*
+ * 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 "ignite/ignite_client.h"
+
+namespace ignite
+{
+
+} // namespace ignite
diff --git a/modules/platforms/cpp/common/Platform.h b/modules/platforms/cpp/common/Platform.h
index 2901abf986..4955529660 100644
--- a/modules/platforms/cpp/common/Platform.h
+++ b/modules/platforms/cpp/common/Platform.h
@@ -17,6 +17,15 @@
 
 #pragma once
 
+/**
+ * Macro SWITCH_WIN_OTHER that uses first option on Windows and second on any other OS.
+ */
+#ifdef WIN32
+#   define SWITCH_WIN_OTHER(x, y) (x)
+#else
+#   define SWITCH_WIN_OTHER(x, y) (y)
+#endif
+
 #define LITTLE_ENDIAN 1
 #define BIG_ENDIAN 2
 
@@ -29,4 +38,5 @@
 #else
 //TODO: Fix this
 #   define BYTE_ORDER LITTLE_ENDIAN
-#endif
\ No newline at end of file
+#endif
+
diff --git a/modules/platforms/cpp/test-common/CMakeLists.txt b/modules/platforms/cpp/test-common/CMakeLists.txt
index a157d5ed98..92485f7f89 100644
--- a/modules/platforms/cpp/test-common/CMakeLists.txt
+++ b/modules/platforms/cpp/test-common/CMakeLists.txt
@@ -19,7 +19,6 @@ project(ignite-test-common)
 
 set(TARGET ${PROJECT_NAME})
 
-#include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${JNI_INCLUDE_DIRS})
 include_directories(include)
 
 set(SOURCES
@@ -32,4 +31,6 @@ add_library(${TARGET} OBJECT ${SOURCES})
 
 set_target_properties(${TARGET} PROPERTIES VERSION ${CMAKE_PROJECT_VERSION})
 set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE 1)
+
+target_link_libraries(${TARGET} ignite-common)
 target_include_directories(${TARGET} INTERFACE include)
diff --git a/modules/platforms/cpp/test-common/include/ignite_node.h b/modules/platforms/cpp/test-common/include/ignite_node.h
index 10bc130b2c..4850e07624 100644
--- a/modules/platforms/cpp/test-common/include/ignite_node.h
+++ b/modules/platforms/cpp/test-common/include/ignite_node.h
@@ -23,40 +23,48 @@
 
 namespace ignite
 {
-    class IgniteNode
-    {
-    public:
-        /**
-         * Constructor.
-         */
-        IgniteNode() = default;
-
-        /**
-         * Destructor.
-         */
-        ~IgniteNode() = default;
-
-        /**
-         * Start node.
-         *
-         * @param dryRun Perform a dry run. Mostly used to ensure that code is compiled and all artifacts are downloaded.
-         */
-        void start(bool dryRun = false);
-
-        /**
-         * Stop node.
-         */
-        void stop();
-
-        /**
-         * Join node process.
-         *
-         * @param timeout Timeout.
-         */
-        void join(std::chrono::milliseconds timeout);
-
-    private:
-        /** Underlying process. */
-        std::unique_ptr<Process> process;
-    };
+
+/**
+ * Represents Ignite server node process.
+ *
+ * Ignite node is started from command line. It is recommended to re-use
+ * a single Ignite node as much as possible to make tests as quick as possible.
+ */
+class IgniteNode
+{
+public:
+    /**
+     * Constructor.
+     */
+    IgniteNode() = default;
+
+    /**
+     * Destructor.
+     */
+    ~IgniteNode() = default;
+
+    /**
+     * Start node.
+     *
+     * @param dryRun Perform a dry run. Mostly used to ensure that code is compiled and all artifacts are downloaded.
+     */
+    void start(bool dryRun = false);
+
+    /**
+     * Stop node.
+     */
+    void stop();
+
+    /**
+     * Join node process.
+     *
+     * @param timeout Timeout.
+     */
+    void join(std::chrono::milliseconds timeout);
+
+private:
+    /** Underlying process. */
+    std::unique_ptr<Process> process;
+};
+
 } // namespace ignite
diff --git a/modules/platforms/cpp/test-common/include/process.h b/modules/platforms/cpp/test-common/include/process.h
index ab45700ccb..4f4707c4fe 100644
--- a/modules/platforms/cpp/test-common/include/process.h
+++ b/modules/platforms/cpp/test-common/include/process.h
@@ -19,48 +19,54 @@
 
 #include <chrono>
 #include <string>
+#include <memory>
 
 namespace ignite
 {
-    class Process
-    {
-    public:
-        /**
-         * Destructor.
-         */
-        virtual ~Process() = default;
 
-        /**
-         * Make new process instance.
-         *
-         * @param command Command.
-         * @param workDir Working directory.
-         * @return Process.
-         */
-        static std::unique_ptr<Process> make(std::string command, std::string workDir);
+/**
+ * Represents system process launched using commandline instruction.
+ */
+class Process
+{
+public:
+    /**
+     * Destructor.
+     */
+    virtual ~Process() = default;
+
+    /**
+     * Make new process instance.
+     *
+     * @param command Command.
+     * @param workDir Working directory.
+     * @return Process.
+     */
+    static std::unique_ptr<Process> make(std::string command, std::string workDir);
+
+    /**
+     * Start process.
+     */
+    virtual bool start() = 0;
 
-        /**
-         * Start process.
-         */
-        virtual bool start() = 0;
+    /**
+     * Kill the process.
+     */
+    virtual void kill() = 0;
 
-        /**
-         * Kill the process.
-         */
-        virtual void kill() = 0;
+    /**
+     * Join process.
+     *
+     * @param timeout Timeout.
+     */
+    virtual void join(std::chrono::milliseconds timeout) = 0;
 
-        /**
-         * Join process.
-         *
-         * @param timeout Timeout.
-         */
-        virtual void join(std::chrono::milliseconds timeout) = 0;
+protected:
+    /**
+     * Constructor.
+     */
+    Process() = default;
+};
 
-    protected:
-        /**
-         * Constructor.
-         */
-        Process() = default;
-    };
 } // namespace ignite
 
diff --git a/modules/platforms/cpp/test-common/include/test_utils.h b/modules/platforms/cpp/test-common/include/test_utils.h
index 01626fd703..3857a321e4 100644
--- a/modules/platforms/cpp/test-common/include/test_utils.h
+++ b/modules/platforms/cpp/test-common/include/test_utils.h
@@ -23,21 +23,23 @@
 
 namespace ignite
 {
-    /**
-     * Resolve IGNITE_HOME directory. Resolution is performed in several steps:
-     * 1) Check for path provided as argument.
-     * 2) Check for environment variable.
-     * 3) Check for current working directory.
-     * Result of these checks are evaluated based on existence of certain predefined folders inside possible Ignite
-     * home. If they are found, IGNITE_HOME is considered resolved.
-     *
-     * @param path Optional path to check.
-     * @return Resolved Ignite home.
-     */
-    std::string resolveIgniteHome(const std::string& path = "");
 
-    /**
-     * Get path to maven executable.
-     */
-    std::string getMavenPath();
+/**
+ * Resolve IGNITE_HOME directory. Resolution is performed in several steps:
+ * 1) Check for path provided as argument.
+ * 2) Check for environment variable.
+ * 3) Check for current working directory.
+ * Result of these checks are evaluated based on existence of certain predefined folders inside possible Ignite
+ * home. If they are found, IGNITE_HOME is considered resolved.
+ *
+ * @param path Optional path to check.
+ * @return Resolved Ignite home.
+ */
+std::string resolveIgniteHome(const std::string& path = "");
+
+/**
+ * Get path to maven executable.
+ */
+std::string getMavenPath();
+
 } // namespace ignite
\ No newline at end of file
diff --git a/modules/platforms/cpp/test-common/src/ignite_node.cpp b/modules/platforms/cpp/test-common/src/ignite_node.cpp
index 560b9f54fd..3c6f7ab6a3 100644
--- a/modules/platforms/cpp/test-common/src/ignite_node.cpp
+++ b/modules/platforms/cpp/test-common/src/ignite_node.cpp
@@ -19,54 +19,61 @@
 #include <stdexcept>
 #include <iostream>
 
+#include "common/Platform.h"
+
 #include "ignite_node.h"
 #include "test_utils.h"
 
-namespace ignite
+namespace
 {
-    void IgniteNode::start(bool dryRun)
-    {
-        std::string home = resolveIgniteHome();
-        if (home.empty())
-            throw std::runtime_error(
-                    "Can not resolve Ignite home directory. Try setting IGNITE_HOME explicitly");
 
-        std::string command =
-#ifdef WIN32
-        "cmd.exe /c ";
-#else
-        "/bin/bash -c ";
-#endif
+/**
+ * System shell command string.
+ */
+constexpr std::string_view SYSTEM_SHELL = SWITCH_WIN_OTHER("cmd.exe /c ", "/bin/bash -c ");
 
-        command += getMavenPath() + " exec:java@platform-test-node-runner";
+} // anonymous namespace
 
-        if (dryRun)
-            command += " -Dexec.args=dry-run";
+namespace ignite
+{
 
-        auto workDir = std::filesystem::path(home) / "modules" / "runner";
+void IgniteNode::start(bool dryRun)
+{
+    std::string home = resolveIgniteHome();
+    if (home.empty())
+        throw std::runtime_error(
+                "Can not resolve Ignite home directory. Try setting IGNITE_HOME explicitly");
 
-        std::cout << "IGNITE_HOME=" << home << std::endl;
-        std::cout << "working dir=" << workDir << std::endl;
-        std::cout << "command=" << command << std::endl;
+    std::string command = std::string(SYSTEM_SHELL) + getMavenPath() + " exec:java@platform-test-node-runner";
 
-        process = Process::make(command, workDir.string());
-        if (!process->start())
-        {
-            process.reset();
+    if (dryRun)
+        command += " -Dexec.args=dry-run";
 
-            throw std::runtime_error("Failed to invoke Ignite command: '" + command + "'");
-        }
-    }
+    auto workDir = std::filesystem::path(home) / "modules" / "runner";
 
-    void IgniteNode::stop()
-    {
-        if (process)
-            process->kill();
-    }
+    std::cout << "IGNITE_HOME=" << home << std::endl;
+    std::cout << "working dir=" << workDir << std::endl;
+    std::cout << "command=" << command << std::endl;
 
-    void IgniteNode::join(std::chrono::milliseconds timeout)
+    process = Process::make(command, workDir.string());
+    if (!process->start())
     {
-        if (process)
-            process->join(timeout);
+        process.reset();
+
+        throw std::runtime_error("Failed to invoke Ignite command: '" + command + "'");
     }
+}
+
+void IgniteNode::stop()
+{
+    if (process)
+        process->kill();
+}
+
+void IgniteNode::join(std::chrono::milliseconds timeout)
+{
+    if (process)
+        process->join(timeout);
+}
+
 } // namespace ignite
\ No newline at end of file
diff --git a/modules/platforms/cpp/test-common/src/process.cpp b/modules/platforms/cpp/test-common/src/process.cpp
index 4911031bbc..f2ce10854a 100644
--- a/modules/platforms/cpp/test-common/src/process.cpp
+++ b/modules/platforms/cpp/test-common/src/process.cpp
@@ -16,8 +16,9 @@
  */
 
 #ifdef WIN32
-#   include <windows.h>
-#   include <tlhelp32.h>
+#   include "win/win_process.h"
+#else
+#   include "linux/linux_process.h"
 #endif
 
 #include <filesystem>
@@ -26,159 +27,16 @@
 
 #include "process.h"
 
-namespace
-{
-#ifdef WIN32
-    /**
-     * Get process tree.
-     * @param processId ID of the parent process.
-     * @return Process tree.
-     */
-    std::vector<DWORD> getProcessTree(DWORD processId) // NOLINT(misc-no-recursion)
-    {
-        std::vector<DWORD> children;
-        PROCESSENTRY32 pe;
-
-        memset(&pe, 0, sizeof(PROCESSENTRY32));
-        pe.dwSize = sizeof(PROCESSENTRY32);
-
-        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-
-        if (Process32First(hSnap, &pe))
-        {
-            BOOL bContinue = TRUE;
-
-            while (bContinue)
-            {
-                if (pe.th32ParentProcessID == processId)
-                    children.push_back(pe.th32ProcessID);
-
-                bContinue = Process32Next(hSnap, &pe);
-            }
-        }
-
-        std::vector<DWORD> tree(children);
-        for (auto procId : children)
-        {
-            std::vector<DWORD> childTree = getProcessTree(procId);
-            tree.insert(tree.end(), childTree.begin(), childTree.end());
-        }
-
-        return tree;
-    }
-
-    /**
-     * Implementation of Process for Windows.
-     */
-    class WinProcess : public ignite::Process
-    {
-    public:
-        /**
-         * Constructor.
-         *
-         * @param command Command.
-         * @param workDir Working directory.
-         */
-        WinProcess(std::string command, std::string workDir) :
-            running(false),
-            command(std::move(command)),
-            workDir(std::move(workDir)),
-            info{}
-        { }
-
-        /**
-         * Destructor.
-         */
-        ~WinProcess() override = default;
-
-
-        /**
-         * Start process.
-         */
-        bool start() override
-        {
-            if (running)
-                return false;
-
-            STARTUPINFO si;
-
-            std::memset(&si, 0, sizeof(si));
-            si.cb = sizeof(si);
-            std::memset(&info, 0, sizeof(info));
-
-            std::vector<char> cmd(command.begin(), command.end());
-            cmd.push_back(0);
-
-            BOOL success = CreateProcess(
-                    NULL, cmd.data(), NULL, NULL,
-                    FALSE, 0, NULL, workDir.c_str(),
-                    &si, &info);
-
-            running = success == TRUE;
-
-            return running;
-        }
-
-        /**
-         * Kill the process.
-         */
-        void kill() override
-        {
-            std::vector<DWORD> processTree = getProcessTree(info.dwProcessId);
-            for (auto procId : processTree)
-            {
-                HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
-                if (hChildProc)
-                {
-                    TerminateProcess(hChildProc, 1);
-                    CloseHandle(hChildProc);
-                }
-            }
-
-            TerminateProcess(info.hProcess, 1);
-
-            CloseHandle( info.hProcess );
-            CloseHandle( info.hThread );
-        }
-
-        /**
-         * Join process.
-         *
-         * @param timeout Timeout.
-         */
-        void join(std::chrono::milliseconds timeout) override
-        {
-            auto msecs = timeout.count() < 0 ? INFINITE : static_cast<DWORD>(timeout.count());
-
-            WaitForSingleObject(info.hProcess, msecs);
-        }
-
-    private:
-        /** Running flag. */
-        bool running;
-
-        /** Command. */
-        const std::string command;
-
-        /** Working directory. */
-        const std::string workDir;
-
-        /** Process information. */
-        PROCESS_INFORMATION info;
-    };
-
-#else // #ifdef WIN32
-
-#endif // #ifdef WIN32
-}
 
 namespace ignite
 {
-    std::unique_ptr<Process> Process::make(std::string command, std::string workDir)
-    {
+
+std::unique_ptr<Process> Process::make(std::string command, std::string workDir)
+{
 #ifdef WIN32
-        return std::unique_ptr<Process>(new WinProcess(std::move(command), std::move(workDir)));
+    return std::unique_ptr<Process>(new win::WinProcess(std::move(command), std::move(workDir)));
 #else
 #endif
-    }
+}
+
 } // namespace ignite
\ No newline at end of file
diff --git a/modules/platforms/cpp/test-common/src/test_utils.cpp b/modules/platforms/cpp/test-common/src/test_utils.cpp
index f6b0a46386..97e811e984 100644
--- a/modules/platforms/cpp/test-common/src/test_utils.cpp
+++ b/modules/platforms/cpp/test-common/src/test_utils.cpp
@@ -24,71 +24,73 @@
 
 namespace ignite
 {
-    /**
-     * Checks if the path looks like binary release home directory.
-     * Internally checks for presence of core library.
-     * @return @c true if the path looks like binary release home directory.
-     */
-    bool looksLikeBinaryReleaseHome(const std::filesystem::path& path)
-    {
-        std::filesystem::path coreLibPath = path / "libs";
-        if (!is_directory(coreLibPath))
-            return false;
-
-        auto iter = std::filesystem::directory_iterator{coreLibPath};
-        return std::any_of(iter, std::filesystem::end(iter), [](auto entry) {
-            const std::filesystem::path& entryPath = entry.path();
-            if (entryPath.extension() != "jar")
-                return false;
 
-            std::string stem = entryPath.stem().string();
-            return stem.find("ignite-core") == 0;
-        });
-    }
-
-    /**
-     * Checks if the path looks like source release home directory.
-     * Internally checks for presence of core source directory.
-     * @return @c true if the path looks like binary release home directory.
-     */
-    bool looksLikeSourceReleaseHome(const std::filesystem::path& path)
-    {
-        std::filesystem::path coreSourcePath =
-                path / "modules" / "core" / "src" / "main" / "java" / "org" / "apache" / "ignite";
+/**
+ * Checks if the path looks like binary release home directory.
+ * Internally checks for presence of core library.
+ * @return @c true if the path looks like binary release home directory.
+ */
+bool looksLikeBinaryReleaseHome(const std::filesystem::path& path)
+{
+    std::filesystem::path coreLibPath = path / "libs";
+    if (!is_directory(coreLibPath))
+        return false;
 
-        return std::filesystem::is_directory(coreSourcePath);
-    }
+    auto iter = std::filesystem::directory_iterator{coreLibPath};
+    return std::any_of(iter, std::filesystem::end(iter), [](auto entry) {
+        const std::filesystem::path& entryPath = entry.path();
+        if (entryPath.extension() != "jar")
+            return false;
 
-    std::string resolveIgniteHome(const std::string& path)
-    {
-        std::error_code error;
+        std::string stem = entryPath.stem().string();
+        return stem.find("ignite-core") == 0;
+    });
+}
 
-        std::filesystem::path home = std::filesystem::canonical(path, error);
-        if (!error && std::filesystem::is_directory(path))
-            return home.string();
+/**
+ * Checks if the path looks like source release home directory.
+ * Internally checks for presence of core source directory.
+ * @return @c true if the path looks like binary release home directory.
+ */
+bool looksLikeSourceReleaseHome(const std::filesystem::path& path)
+{
+    std::filesystem::path coreSourcePath =
+            path / "modules" / "core" / "src" / "main" / "java" / "org" / "apache" / "ignite";
 
-        const char *env = std::getenv("IGNITE_HOME");
-        if (env)
-        {
-            home = std::filesystem::canonical(env, error);
-            if (!error && std::filesystem::is_directory(home))
-                return home.string();
-        }
+    return std::filesystem::is_directory(coreSourcePath);
+}
 
-        home = std::filesystem::current_path();
-        while (!home.empty() && home.has_relative_path())
-        {
-            if (looksLikeBinaryReleaseHome(home) || looksLikeSourceReleaseHome(home))
-                return home.string();
+std::string resolveIgniteHome(const std::string& path)
+{
+    std::error_code error;
 
-            home = home.parent_path();
-        }
+    std::filesystem::path home = std::filesystem::canonical(path, error);
+    if (!error && std::filesystem::is_directory(path))
         return home.string();
+
+    const char *env = std::getenv("IGNITE_HOME");
+    if (env)
+    {
+        home = std::filesystem::canonical(env, error);
+        if (!error && std::filesystem::is_directory(home))
+            return home.string();
     }
 
-    std::string getMavenPath()
+    home = std::filesystem::current_path();
+    while (!home.empty() && home.has_relative_path())
     {
-        // Currently, we only support systems with "mvn" command in PATH
-        return "mvn";
+        if (looksLikeBinaryReleaseHome(home) || looksLikeSourceReleaseHome(home))
+            return home.string();
+
+        home = home.parent_path();
     }
+    return home.string();
+}
+
+std::string getMavenPath()
+{
+    // Currently, we only support systems with "mvn" command in PATH
+    return "mvn";
+}
+
 } // namespace ignite
\ No newline at end of file
diff --git a/modules/platforms/cpp/test-common/src/win/win_process.h b/modules/platforms/cpp/test-common/src/win/win_process.h
new file mode 100644
index 0000000000..b0c29c5941
--- /dev/null
+++ b/modules/platforms/cpp/test-common/src/win/win_process.h
@@ -0,0 +1,173 @@
+/*
+ * 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
+
+// It's OK that this code is entirely in header as it only supposed to be included from a single file.
+
+#include <windows.h>
+#include <tlhelp32.h>
+
+#include <vector>
+#include <chrono>
+#include <string>
+
+#include "process.h"
+
+namespace ignite::win
+{
+
+/**
+ * Get process tree.
+ * @param processId ID of the parent process.
+ * @return Process tree.
+ */
+std::vector<DWORD> getProcessTree(DWORD processId) // NOLINT(misc-no-recursion)
+{
+    std::vector<DWORD> children;
+    PROCESSENTRY32 pe;
+
+    memset(&pe, 0, sizeof(PROCESSENTRY32));
+    pe.dwSize = sizeof(PROCESSENTRY32);
+
+    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+    if (Process32First(hSnap, &pe))
+    {
+        BOOL bContinue = TRUE;
+
+        while (bContinue)
+        {
+            if (pe.th32ParentProcessID == processId)
+                children.push_back(pe.th32ProcessID);
+
+            bContinue = Process32Next(hSnap, &pe);
+        }
+    }
+
+    std::vector<DWORD> tree(children);
+    for (auto procId : children)
+    {
+        std::vector<DWORD> childTree = getProcessTree(procId);
+        tree.insert(tree.end(), childTree.begin(), childTree.end());
+    }
+
+    return tree;
+}
+
+/**
+ * Implementation of Process for Windows.
+ */
+class WinProcess : public ignite::Process
+{
+public:
+    /**
+     * Constructor.
+     *
+     * @param command Command.
+     * @param workDir Working directory.
+     */
+    WinProcess(std::string command, std::string workDir) :
+            running(false),
+            command(std::move(command)),
+            workDir(std::move(workDir)),
+            info{}
+    { }
+
+    /**
+     * Destructor.
+     */
+    ~WinProcess() override = default;
+
+
+    /**
+     * Start process.
+     */
+    bool start() override
+    {
+        if (running)
+            return false;
+
+        STARTUPINFO si;
+
+        std::memset(&si, 0, sizeof(si));
+        si.cb = sizeof(si);
+        std::memset(&info, 0, sizeof(info));
+
+        std::vector<char> cmd(command.begin(), command.end());
+        cmd.push_back(0);
+
+        BOOL success = CreateProcess(
+                NULL, cmd.data(), NULL, NULL,
+                FALSE, 0, NULL, workDir.c_str(),
+                &si, &info);
+
+        running = success == TRUE;
+
+        return running;
+    }
+
+    /**
+     * Kill the process.
+     */
+    void kill() override
+    {
+        std::vector<DWORD> processTree = getProcessTree(info.dwProcessId);
+        for (auto procId : processTree)
+        {
+            HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
+            if (hChildProc)
+            {
+                TerminateProcess(hChildProc, 1);
+                CloseHandle(hChildProc);
+            }
+        }
+
+        TerminateProcess(info.hProcess, 1);
+
+        CloseHandle( info.hProcess );
+        CloseHandle( info.hThread );
+    }
+
+    /**
+     * Join process.
+     *
+     * @param timeout Timeout.
+     */
+    void join(std::chrono::milliseconds timeout) override
+    {
+        auto msecs = timeout.count() < 0 ? INFINITE : static_cast<DWORD>(timeout.count());
+
+        WaitForSingleObject(info.hProcess, msecs);
+    }
+
+private:
+    /** Running flag. */
+    bool running;
+
+    /** Command. */
+    const std::string command;
+
+    /** Working directory. */
+    const std::string workDir;
+
+    /** Process information. */
+    PROCESS_INFORMATION info;
+};
+
+} // namespace ignite::win
+