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:47 UTC
[ignite-3] 06/17: IGNITE-17424 Start and stop Ignite node
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 61c64082a870d209db6b3648961b143eb61befff
Author: Igor Sapego <is...@apache.org>
AuthorDate: Mon Aug 29 23:02:00 2022 +0400
IGNITE-17424 Start and stop Ignite node
---
.../cpp/client-test/src/ignite_client_test.cpp | 16 +-
modules/platforms/cpp/test-common/CMakeLists.txt | 1 +
.../cpp/test-common/include/ignite_node.h | 52 ++++---
.../include/{ignite_node.h => process.h} | 46 +++---
.../platforms/cpp/test-common/include/test_utils.h | 19 ---
.../platforms/cpp/test-common/src/ignite_node.cpp | 51 ++++--
modules/platforms/cpp/test-common/src/process.cpp | 173 +++++++++++++++++++++
.../platforms/cpp/test-common/src/test_utils.cpp | 18 ---
8 files changed, 263 insertions(+), 113 deletions(-)
diff --git a/modules/platforms/cpp/client-test/src/ignite_client_test.cpp b/modules/platforms/cpp/client-test/src/ignite_client_test.cpp
index 2413b1839b..7fc40ed724 100644
--- a/modules/platforms/cpp/client-test/src/ignite_client_test.cpp
+++ b/modules/platforms/cpp/client-test/src/ignite_client_test.cpp
@@ -42,25 +42,11 @@ protected:
TEST_F(ClientTest, TestTest)
{
- std::cout << "Hello" << std::endl;
-
ignite::IgniteNode node;
node.start();
- for (int i = 0; i < 20; ++i)
- {
- std::cout << node.getOutput();
-
- std::this_thread::sleep_for(std::chrono::seconds(1));
- }
+ std::this_thread::sleep_for(std::chrono::seconds(20));
node.stop();
-
- for (int i = 0; i < 2; ++i)
- {
- std::cout << node.getOutput();
-
- std::this_thread::sleep_for(std::chrono::seconds(1));
- }
}
\ No newline at end of file
diff --git a/modules/platforms/cpp/test-common/CMakeLists.txt b/modules/platforms/cpp/test-common/CMakeLists.txt
index 396ee4ed72..a157d5ed98 100644
--- a/modules/platforms/cpp/test-common/CMakeLists.txt
+++ b/modules/platforms/cpp/test-common/CMakeLists.txt
@@ -24,6 +24,7 @@ include_directories(include)
set(SOURCES
src/ignite_node.cpp
+ src/process.cpp
src/test_utils.cpp
)
diff --git a/modules/platforms/cpp/test-common/include/ignite_node.h b/modules/platforms/cpp/test-common/include/ignite_node.h
index 224aa3e124..490a7985e0 100644
--- a/modules/platforms/cpp/test-common/include/ignite_node.h
+++ b/modules/platforms/cpp/test-common/include/ignite_node.h
@@ -15,46 +15,54 @@
* limitations under the License.
*/
-#ifndef TEST_COMMON_IGNITE_NODE
-#define TEST_COMMON_IGNITE_NODE
+#pragma once
-//#include <cstdio>
+#include "process.h"
namespace ignite
{
class IgniteNode
{
public:
-// /**
-// * Constructor.
-// */
-// IgniteNode() = default;
+ /**
+ * Constructor.
+ */
+ IgniteNode() = default;
-// /**
-// * Destructor.
-// */
-// ~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();
+ void start(bool dryRun = false);
/**
* Stop node.
*/
void stop();
- /**
- * Get current node output.
- *
- * @param max Max bytes to get.
- * @return Output.
- */
- std::string getOutput(int max = 1024);
+// /**
+// * Check whether node is still running.
+// *
+// * @return @c true if the node is running.
+// */
+// bool isRunning();
+//
+// /**
+// * Get current node output.
+// *
+// * @param max Max bytes to get.
+// * @return Output.
+// */
+// std::string getOutput(int max = 1024);
+
private:
- FILE* stream;
+ /** Underlying process. */
+ std::unique_ptr<Process> process;
};
} // namespace ignite
-
-#endif // TEST_COMMON_IGNITE_NODE
diff --git a/modules/platforms/cpp/test-common/include/ignite_node.h b/modules/platforms/cpp/test-common/include/process.h
similarity index 62%
copy from modules/platforms/cpp/test-common/include/ignite_node.h
copy to modules/platforms/cpp/test-common/include/process.h
index 224aa3e124..b2d6d50121 100644
--- a/modules/platforms/cpp/test-common/include/ignite_node.h
+++ b/modules/platforms/cpp/test-common/include/process.h
@@ -15,46 +15,44 @@
* limitations under the License.
*/
-#ifndef TEST_COMMON_IGNITE_NODE
-#define TEST_COMMON_IGNITE_NODE
+#pragma once
-//#include <cstdio>
+#include <string>
namespace ignite
{
- class IgniteNode
+ class Process
{
public:
-// /**
-// * Constructor.
-// */
-// IgniteNode() = default;
+ /**
+ * Destructor.
+ */
+ virtual ~Process() = default;
-// /**
-// * Destructor.
-// */
-// ~IgniteNode() = 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 node.
+ * Start process.
*/
- void start();
+ virtual bool start() = 0;
/**
- * Stop node.
+ * Stop process.
*/
- void stop();
+ virtual void stop() = 0;
+ protected:
/**
- * Get current node output.
- *
- * @param max Max bytes to get.
- * @return Output.
+ * Constructor.
*/
- std::string getOutput(int max = 1024);
- private:
- FILE* stream;
+ Process() = default;
};
} // namespace ignite
-#endif // TEST_COMMON_IGNITE_NODE
diff --git a/modules/platforms/cpp/test-common/include/test_utils.h b/modules/platforms/cpp/test-common/include/test_utils.h
index ca0d00a51f..01626fd703 100644
--- a/modules/platforms/cpp/test-common/include/test_utils.h
+++ b/modules/platforms/cpp/test-common/include/test_utils.h
@@ -40,23 +40,4 @@ namespace ignite
* Get path to maven executable.
*/
std::string getMavenPath();
-
- /**
- * Open process.
- *
- * @param command System shell command line instruction.
- * @param type Mode of the returned process output stream. Can be one of the following:
- * "r" - The calling process can read the spawned command's standard output using the returned stream.
- * "w" - The calling process can write to the spawned command's standard input using the returned stream.
- * @return File stream for the process.
- */
- FILE* processOpen(const char *command, const char *type);
-
- /**
- * Waits for the associated process to terminate and returns the exit status of the command.
- *
- * @param stream Return value from the previous call to processOpen().
- * @return Returns the exit status of the terminating command processor, or -1 if an error occurs.
- */
- int processClose(FILE* stream);
} // 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 1fb4bfb6eb..47807989a8 100644
--- a/modules/platforms/cpp/test-common/src/ignite_node.cpp
+++ b/modules/platforms/cpp/test-common/src/ignite_node.cpp
@@ -15,17 +15,18 @@
* limitations under the License.
*/
-#include <iostream>
+#include <filesystem>
#include <stdexcept>
#include <vector>
#include <utility>
+#include <iostream>
#include "ignite_node.h"
#include "test_utils.h"
namespace ignite
{
- void IgniteNode::start()
+ void IgniteNode::start(bool dryRun)
{
std::string home = resolveIgniteHome();
if (home.empty())
@@ -39,24 +40,44 @@ namespace ignite
"/bin/bash -c ";
#endif
- command += getMavenPath() + " " + "exec:java@platform-test-node-runner";
+ command += getMavenPath() + " exec:java@platform-test-node-runner";
+
+ if (dryRun)
+ command += " -Dexec.args=dry-run";
+
+ auto workDir = std::filesystem::path(home) / "modules" / "runner";
+
+ std::cout << "IGNITE_HOME=" << home << std::endl;
+ std::cout << "working dir=" << workDir << std::endl;
+ std::cout << "command=" << command << std::endl;
- stream = processOpen(command.c_str(), "r");
+ process = Process::make(command, workDir.string());
+ if (!process->start())
+ {
+ throw std::runtime_error("Failed to invoke Ignite command: '" + command + "'");
+
+ process.reset();
+ }
}
void IgniteNode::stop()
{
- if (stream)
- processClose(stream);
+ if (process)
+ process->stop();
}
- std::string IgniteNode::getOutput(int max)
- {
- std::string buffer(max, 0);
-
- size_t actual = std::fread(buffer.data(), 1, max, stream);
- buffer.resize(actual);
-
- return buffer;
- }
+// bool IgniteNode::isRunning()
+// {
+// return std::feof(stream) == 0 && std::ferror(stream) == 0;
+// }
+//
+// std::string IgniteNode::getOutput(int max)
+// {
+// std::string buffer(max, 0);
+//
+// size_t actual = std::fread(buffer.data(), 1, max, stream);
+// buffer.resize(actual);
+//
+// return buffer;
+// }
} // 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
new file mode 100644
index 0000000000..4620b53aec
--- /dev/null
+++ b/modules/platforms/cpp/test-common/src/process.cpp
@@ -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.
+ */
+
+#ifdef WIN32
+# include <windows.h>
+# include <tlhelp32.h>
+#endif // WIN32
+
+#include <filesystem>
+#include <utility>
+#include <vector>
+
+#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)
+ {
+ 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;
+ }
+
+ /**
+ * Stop process.
+ */
+ void stop() 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);
+
+ WaitForSingleObject( info.hProcess, INFINITE );
+
+ CloseHandle( info.hProcess );
+ CloseHandle( info.hThread );
+ }
+
+ private:
+ /** Running flag. */
+ bool running;
+
+ /** Command. */
+ const std::string command;
+
+ /** Working directory. */
+ const std::string workDir;
+
+ /** Process information. */
+ PROCESS_INFORMATION info;
+ };
+
+#else
+#endif
+}
+
+namespace ignite
+{
+ 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)));
+#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 65fe5b8975..f6b0a46386 100644
--- a/modules/platforms/cpp/test-common/src/test_utils.cpp
+++ b/modules/platforms/cpp/test-common/src/test_utils.cpp
@@ -91,22 +91,4 @@ namespace ignite
// Currently, we only support systems with "mvn" command in PATH
return "mvn";
}
-
- FILE *processOpen(const char *command, const char *type)
- {
-#ifdef WIN32
- return _popen(command, type);
-#else
- return popen(command, type);
-#endif
- }
-
- int processClose(FILE *stream)
- {
-#ifdef WIN32
- return _pclose(stream);
-#else
- return pclose(stream);
-#endif
- }
} // namespace ignite
\ No newline at end of file