Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
# Define project (multiple EXEs)
project(ProcessControlUnitTests VERSION 1.0 LANGUAGES CXX)
# Surrogate repeater executable
add_executable(UnitTest_ProcessControlApp
"process_control_app.cpp"
"process_control_ifc.h")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(UnitTest_ProcessControlApp ${CMAKE_THREAD_LIBS_INIT} stdc++fs)
if (WIN32)
target_link_libraries(UnitTest_ProcessControlApp Ws2_32 Winmm Rpcrt4.lib)
else()
target_link_libraries(UnitTest_ProcessControlApp ${CMAKE_DL_LIBS} rt)
endif()
else()
target_link_libraries(UnitTest_ProcessControlApp Ws2_32 Winmm Rpcrt4.lib)
endif()
# Communication tests executable
add_executable(UnitTest_ProcessControl
"main.cpp"
"process_control_tests.cpp" "process_control_ifc.h")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(UnitTest_ProcessControl GTest::GTest ${CMAKE_THREAD_LIBS_INIT} stdc++fs)
if (WIN32)
target_link_libraries(UnitTest_ProcessControl Ws2_32 Winmm Rpcrt4.lib)
else()
target_link_libraries(UnitTest_ProcessControl ${CMAKE_DL_LIBS} rt)
endif()
else()
target_link_libraries(UnitTest_ProcessControl GTest::GTest Rpcrt4.lib)
endif()
# Add the communication unittest
add_test(NAME UnitTest_ProcessControl COMMAND UnitTest_ProcessControl)
# Execute the test
add_custom_command(TARGET UnitTest_ProcessControl POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_ProcessControl>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_ProcessControl.xml
VERBATIM
)
# Build dependencies
add_dependencies(UnitTest_ProcessControlApp dependency_sdv_components)
add_dependencies(UnitTest_ProcessControl UnitTest_ProcessControlApp)
add_dependencies(UnitTest_ProcessControl dependency_sdv_components)

View File

@@ -0,0 +1,14 @@
#include "gtest/gtest.h"
#include "../../../global/process_watchdog.h"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
#else
extern "C" int main(int argc, char* argv[])
#endif
{
CProcessWatchdog watchdog;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,139 @@
#include <sstream>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <string>
#include <iostream>
#include <fstream>
#include <support/mem_access.h>
#include <support/app_control.h>
#include "../../../sdv_services/process_control/process_control.cpp"
#include "process_control_ifc.h"
#include <cstdlib>
#include "../../../global/trace.h"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
#else
extern "C" int main(int argc, char* argv[])
#endif
{
std::cout << GetTimestamp() << "Startup process control application..." << std::endl;
// The first argument is the name of the application
// The second argument is the operation mode
if (argc < 2)
{
std::cout << GetTimestamp() << "Invalid arguments..." << std::endl;
return -1;
}
EOperatingmode eMode = static_cast<EOperatingmode>(std::atoi(sdv::MakeAnsiString(argv[1]).c_str()));
sdv::app::CAppControl appcontrol;
if (!appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"))
{
std::cout << GetTimestamp() << "Failed to start app control..." << std::endl;
return -1;
}
int nResult = 0;
switch (eMode)
{
case EOperatingmode::normal_shutdown_1000ms:
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << GetTimestamp() << "Normal shutdown after 1000ms" << std::endl;
break;
case EOperatingmode::emergency_exit_1000ms:
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << GetTimestamp() << "Emergency exit after 1000ms" << std::endl;
#ifdef _MSC_VER
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#ifdef _WIN32
TerminateProcess(GetCurrentProcess(), static_cast<UINT>(-20));
#else
std::_Exit(-20);
#endif
break;
case EOperatingmode::wait_for_process:
if (argc < 3)
{
std::cout << GetTimestamp() << "Invalid arguments..." << std::endl;
return -1;
}
{
std::string ssProcessID = sdv::MakeAnsiString(argv[2]);
char* szEnd = nullptr;
sdv::process::TProcessID tProcessID = static_cast<sdv::process::TProcessID>(std::strtoull(ssProcessID.c_str(), &szEnd, 10));
if (!tProcessID)
{
std::cout << GetTimestamp() << "Expecting a process ID..." << std::endl;
nResult = -3;
break;
}
std::cout << GetTimestamp() << "Waiting for process with PID#" << std::dec << tProcessID << std::endl;
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
uint32_t uiMon = control.RegisterMonitor(tProcessID, &monitor);
if (!uiMon)
{
std::cout << GetTimestamp() << "Could not register monitor..." << std::endl;
nResult = -4;
break;
}
if (!monitor.Wait5000ms())
{
std::cout << GetTimestamp() << "Wait failed for monitor..." << std::endl;
nResult = -20;
control.UnregisterMonitor(uiMon);
break;
}
std::cout << GetTimestamp() << "Return value of first process: " << monitor.GetRetValue() << std::endl;
switch (monitor.GetRetValue())
{
case 0: break;
case -20: nResult = -10; break;
default: nResult = -20; break;
}
control.UnregisterMonitor(uiMon);
control.Shutdown(); // Needed to prevent clash with core
}
break;
case EOperatingmode::terminate_process:
if (argc < 3)
{
std::cout << GetTimestamp() << "Invalid arguments..." << std::endl;
return -1;
}
{
std::string ssProcessID = sdv::MakeAnsiString(argv[2]);
char* szEnd = nullptr;
sdv::process::TProcessID tProcessID = static_cast<sdv::process::TProcessID>(std::strtoull(ssProcessID.c_str(), &szEnd, 10));
if (!tProcessID)
{
std::cout << GetTimestamp() << "Expecting a process ID..." << std::endl;
nResult = -3;
break;
}
std::cout << GetTimestamp() << "Terminate process with PID#" << std::dec << tProcessID << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Make certain, that the first process is actually running...
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
nResult = control.Terminate(tProcessID) ? 0 : -20;
control.Shutdown(); // Needed to prevent clash with core
}
break;
default: // Unknown mode
std::cout << GetTimestamp() << "Invalid arguments..." << std::endl;
nResult = -2;
break;
}
appcontrol.Shutdown();
// Done....
return nResult;
}

View File

@@ -0,0 +1,91 @@
#ifndef PROCESS_CONTROL_IFC_H
#define PROCESS_CONTROL_IFC_H
/**
* @brief Process control application parameters.
* @details The operating mode is the first parameter of the application.
*/
enum class EOperatingmode : uint32_t
{
normal_shutdown_1000ms, ///< Proper shutdown after 1000ms; exit code = 0
emergency_exit_1000ms, ///< Emergency exit after 1000ms; exit code = -20
wait_for_process, ///< Wait for process end; then shutdown; exit code = 0 on proper shutdown, -10 on emergency exit, -20 on timeout
terminate_process, ///< Terminate the first process; then shutdown; exit code = 0
};
/**
* @brief Process monitor helper class
*/
class CProcessMonitorHelper : public sdv::IInterfaceAccess, public sdv::process::IProcessLifetimeCallback
{
public:
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(sdv::process::IProcessLifetimeCallback)
END_SDV_INTERFACE_MAP()
/**
* @brief Called when the process was terminated. Overload of sdv::process::IProcessLifetimeCallback::ProcessTerminated.
* @remarks The process return value is not always valid. The validity depends on the support of the underlying system.
* @param[in] tProcessID The process ID of the process being terminated.
* @param[in] iRetValue Process return value or 0 when not supported.
*/
virtual void ProcessTerminated(/*in*/ sdv::process::TProcessID tProcessID, /*in*/ int64_t iRetValue) override
{
std::unique_lock<std::mutex> lock(m_mtxTerminate);
m_tProcessID = tProcessID;
m_iRetValue = iRetValue;
m_bCalled = true;
lock.unlock();
m_cvTerminate.notify_all();
}
/**
* @brief Wait for 5000ms for the process to terminate.
* @return Returns 'true' on successful terminate; 'false' due to a timeout.
*/
bool Wait5000ms()
{
std::unique_lock<std::mutex> lock(m_mtxTerminate);
std::chrono::high_resolution_clock::time_point tpStart = std::chrono::high_resolution_clock::now();
while (!m_bCalled && std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - tpStart).count() < 5.0)
{
m_cvTerminate.wait_for(lock, std::chrono::milliseconds(30));
}
std::cout << GetTimestamp() << "Process PID#" << std::dec << m_tProcessID << " has " << (m_bCalled ? "" : "not ") << "terminated." << std::endl;
return m_bCalled;
}
/**
* @brief Get the process ID (to be called after successful termination).
* @return The process ID provided by the callback event.
*/
sdv::process::TProcessID GetProcessID() const
{
std::unique_lock<std::mutex> lock(m_mtxTerminate);
return m_tProcessID;
}
/**
* @brief Get the return value (to be called after successful termination).
* @return The return value provided by the callback event.
*/
int64_t GetRetValue() const
{
std::unique_lock<std::mutex> lock(m_mtxTerminate);
return m_iRetValue;
}
private:
mutable std::mutex m_mtxTerminate; ///< Mutex for process termination conditional variable.
std::condition_variable m_cvTerminate; ///< Process termination conditional variable.
sdv::process::TProcessID m_tProcessID = 0; ///< Process ID of terminated process.
int64_t m_iRetValue = -100; ///< Process return value.
bool m_bCalled = false; ///< Set when called (to prevent waiting for condition var).
};
#endif // !defined PROCESS_CONTROL_IFC_H

View File

@@ -0,0 +1,649 @@
#include "../../include/gtest_custom.h"
#include <support/sdv_core.h>
#include <support/app_control.h>
#include <interfaces/process.h>
#include "../../../sdv_services/process_control/process_control.cpp"
#include "process_control_ifc.h"
#include "../../../global/trace.h"
TEST(ProcessControlTest, Instantiate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessControl control;
EXPECT_EQ(control.GetProcessID(), static_cast<sdv::process::TProcessID>(getpid()));
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
std::cout << GetTimestamp() << "Initiate execution..." << std::endl;
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID, 0u);
std::cout << GetTimestamp() << "Execution initiated. Waiting for finalization..." << std::endl;
EXPECT_TRUE(control.WaitForTerminate(tProcessID, 5000));
std::cout << GetTimestamp() << "Process execution finalized..." << std::endl;
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteProcessEmergencyExit)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
std::cout << GetTimestamp() << "Initiate execution..." << std::endl;
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID, 0u);
std::cout << GetTimestamp() << "Execution initiated. Waiting for finalization..." << std::endl;
EXPECT_TRUE(control.WaitForTerminate(tProcessID, 5000));
std::cout << GetTimestamp() << "Process execution finalized..." << std::endl;
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteProcessNormalShutdownWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie = control.RegisterMonitor(tProcessID, &monitor);
EXPECT_NE(uiCookie, 0u);
EXPECT_TRUE(monitor.Wait5000ms());
EXPECT_EQ(monitor.GetProcessID(), tProcessID);
EXPECT_EQ(monitor.GetRetValue(), 0);
control.UnregisterMonitor(uiCookie);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteProcessEmergencyExitWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie = control.RegisterMonitor(tProcessID, &monitor);
EXPECT_NE(uiCookie, 0u);
EXPECT_TRUE(monitor.Wait5000ms());
EXPECT_EQ(monitor.GetProcessID(), tProcessID);
EXPECT_EQ(monitor.GetRetValue(), -20);
control.UnregisterMonitor(uiCookie);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteMultiProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID1 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
std::cout << GetTimestamp() << "Process#1 execution initiated PID#" << tProcessID1 << std::endl;
EXPECT_NE(tProcessID1, 0u);
seqArgs.clear();
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::wait_for_process)));
seqArgs.push_back(std::to_string(tProcessID1));
sdv::process::TProcessID tProcessID2 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
std::cout << GetTimestamp() << "Process#2 execution initiated PID#" << tProcessID2 << std::endl;
EXPECT_NE(tProcessID2, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID1, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID2, &monitor2);
EXPECT_NE(uiCookie2, 0u);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_TRUE(monitor2.Wait5000ms());
EXPECT_EQ(monitor1.GetProcessID(), tProcessID1);
EXPECT_EQ(monitor1.GetRetValue(), 0);
EXPECT_EQ(monitor2.GetProcessID(), tProcessID2);
EXPECT_EQ(monitor2.GetRetValue(), 0);
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie2);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteMultiEmergencyAccess)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
sdv::process::TProcessID tProcessID1 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID1, 0u);
seqArgs.clear();
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::wait_for_process)));
seqArgs.push_back(std::to_string(tProcessID1));
sdv::process::TProcessID tProcessID2 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID2, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID1, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID2, &monitor2);
EXPECT_NE(uiCookie2, 0u);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_TRUE(monitor2.Wait5000ms());
EXPECT_EQ(monitor1.GetProcessID(), tProcessID1);
EXPECT_EQ(monitor1.GetRetValue(), -20);
EXPECT_EQ(monitor2.GetProcessID(), tProcessID2);
// NOTE: The process #2 doesn't have the rights to get the exit code of process #1. Therefore it returns 0.
//EXPECT_EQ(monitor2.GetRetValue(), -10);
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie2);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteProcessAndTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie = control.RegisterMonitor(tProcessID, &monitor);
EXPECT_NE(uiCookie, 0u);
bool bTerminateResult = false;
std::thread thread([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
bTerminateResult = control.Terminate(tProcessID);
});
EXPECT_TRUE(monitor.Wait5000ms());
thread.join();
EXPECT_TRUE(bTerminateResult);
EXPECT_EQ(monitor.GetProcessID(), tProcessID);
EXPECT_EQ(monitor.GetRetValue(), -100);
control.UnregisterMonitor(uiCookie);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ParentRightsExecuteMultiTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
sdv::process::TProcessID tProcessID1 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID1, 0u);
seqArgs.clear();
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::terminate_process)));
seqArgs.push_back(std::to_string(tProcessID1));
sdv::process::TProcessID tProcessID2 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID2, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID1, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID2, &monitor2);
EXPECT_NE(uiCookie2, 0u);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_TRUE(monitor2.Wait5000ms());
EXPECT_EQ(monitor1.GetProcessID(), tProcessID1);
EXPECT_EQ(monitor1.GetRetValue(), -100);
EXPECT_EQ(monitor2.GetProcessID(), tProcessID2);
EXPECT_EQ(monitor2.GetRetValue(), 0);
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie2);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
std::cout << GetTimestamp() << "Initiate execution..." << std::endl;
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID, 0u);
std::cout << GetTimestamp() << "Execution initiated. Waiting for finalization..." << std::endl;
EXPECT_TRUE(control.WaitForTerminate(tProcessID, 5000));
std::cout << GetTimestamp() << "Process execution finalized..." << std::endl;
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteProcessEmergencyExit)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
std::cout << GetTimestamp() << "Initiate execution..." << std::endl;
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID, 0u);
std::cout << GetTimestamp() << "Execution initiated. Waiting for finalization..." << std::endl;
EXPECT_TRUE(control.WaitForTerminate(tProcessID, 5000));
std::cout << GetTimestamp() << "Process execution finalized..." << std::endl;
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteProcessNormalShutdownWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie = control.RegisterMonitor(tProcessID, &monitor);
EXPECT_NE(uiCookie, 0u);
EXPECT_TRUE(monitor.Wait5000ms());
EXPECT_EQ(monitor.GetProcessID(), tProcessID);
EXPECT_EQ(monitor.GetRetValue(), 0);
control.UnregisterMonitor(uiCookie);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteProcessEmergencyExitWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie = control.RegisterMonitor(tProcessID, &monitor);
EXPECT_NE(uiCookie, 0u);
EXPECT_TRUE(monitor.Wait5000ms());
EXPECT_EQ(monitor.GetProcessID(), tProcessID);
EXPECT_EQ(monitor.GetRetValue(), -20);
control.UnregisterMonitor(uiCookie);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteMultiProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID1 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID1, 0u);
seqArgs.clear();
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::wait_for_process)));
seqArgs.push_back(std::to_string(tProcessID1));
sdv::process::TProcessID tProcessID2 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID2, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID1, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID2, &monitor2);
EXPECT_NE(uiCookie2, 0u);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_TRUE(monitor2.Wait5000ms());
EXPECT_EQ(monitor1.GetProcessID(), tProcessID1);
EXPECT_EQ(monitor1.GetRetValue(), 0);
EXPECT_EQ(monitor2.GetProcessID(), tProcessID2);
EXPECT_EQ(monitor2.GetRetValue(), 0);
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie2);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteMultiEmergencyAccess)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
sdv::process::TProcessID tProcessID1 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID1, 0u);
seqArgs.clear();
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::wait_for_process)));
seqArgs.push_back(std::to_string(tProcessID1));
sdv::process::TProcessID tProcessID2 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID2, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID1, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID2, &monitor2);
EXPECT_NE(uiCookie2, 0u);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_TRUE(monitor2.Wait5000ms());
EXPECT_EQ(monitor1.GetProcessID(), tProcessID1);
EXPECT_EQ(monitor1.GetRetValue(), -20);
EXPECT_EQ(monitor2.GetProcessID(), tProcessID2);
// NOTE: The process #2 doesn't have the rights to get the exit code of process #1. Therefore it returns 0.
//EXPECT_EQ(monitor2.GetRetValue(), -10);
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie2);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteProcessAndTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie = control.RegisterMonitor(tProcessID, &monitor);
EXPECT_NE(uiCookie, 0u);
bool bTerminateResult = false;
std::thread thread([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
bTerminateResult = control.Terminate(tProcessID);
});
EXPECT_TRUE(monitor.Wait5000ms());
thread.join();
EXPECT_TRUE(bTerminateResult);
EXPECT_EQ(monitor.GetProcessID(), tProcessID);
EXPECT_EQ(monitor.GetRetValue(), -100);
control.UnregisterMonitor(uiCookie);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ReducedRightsExecuteMultiTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::emergency_exit_1000ms)));
sdv::process::TProcessID tProcessID1 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID1, 0u);
seqArgs.clear();
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::terminate_process)));
seqArgs.push_back(std::to_string(tProcessID1));
sdv::process::TProcessID tProcessID2 = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::reduced_rights);
EXPECT_NE(tProcessID2, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID1, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID2, &monitor2);
EXPECT_NE(uiCookie2, 0u);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_TRUE(monitor2.Wait5000ms());
EXPECT_EQ(monitor1.GetProcessID(), tProcessID1);
EXPECT_EQ(monitor1.GetRetValue(), -100);
EXPECT_EQ(monitor2.GetProcessID(), tProcessID2);
EXPECT_EQ(monitor2.GetRetValue(), 0);
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie2);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}
TEST(ProcessControlTest, ExecuteProcessNormalShutdownWithMultipleMonitors)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessMonitorHelper monitor3;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
const std::string ssModule = "UnitTest_ProcessControlApp";
#endif
sdv::sequence<sdv::u8string> seqArgs;
seqArgs.push_back(std::to_string(static_cast<uint32_t>(EOperatingmode::normal_shutdown_1000ms)));
sdv::process::TProcessID tProcessID = control.Execute(ssModule, seqArgs, sdv::process::EProcessRights::parent_rights);
EXPECT_NE(tProcessID, 0u);
uint32_t uiCookie1 = control.RegisterMonitor(tProcessID, &monitor1);
EXPECT_NE(uiCookie1, 0u);
uint32_t uiCookie2 = control.RegisterMonitor(tProcessID, &monitor2);
EXPECT_NE(uiCookie2, 0u);
uint32_t uiCookie3 = control.RegisterMonitor(tProcessID, &monitor3);
EXPECT_NE(uiCookie3, 0u);
control.UnregisterMonitor(uiCookie2);
EXPECT_TRUE(monitor1.Wait5000ms());
EXPECT_FALSE(monitor2.Wait5000ms());
EXPECT_TRUE(monitor3.Wait5000ms());
control.UnregisterMonitor(uiCookie1);
control.UnregisterMonitor(uiCookie3);
control.Shutdown(); // Needed to prevent clash with core
appcontrol.Shutdown();
}