mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-07-02 05:35:11 +00:00
34
tests/unit_tests/core_loader/CMakeLists.txt
Normal file
34
tests/unit_tests/core_loader/CMakeLists.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
# Define project (multiple EXEs)
|
||||
project(CoreLoaderTests VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# BasicTypes unit test executable
|
||||
add_executable(UnitTest_CoreLoader
|
||||
"core_loader_test.cpp"
|
||||
"main.cpp")
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_link_libraries(UnitTest_CoreLoader GTest::GTest ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} stdc++fs)
|
||||
else()
|
||||
target_link_libraries(UnitTest_CoreLoader GTest::GTest)
|
||||
endif()
|
||||
|
||||
# BasicTypes unit test executable
|
||||
add_executable(UnitTest_CoreLoader_TestApp
|
||||
"test_app.cpp")
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_link_libraries(UnitTest_CoreLoader_TestApp ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} stdc++fs)
|
||||
else()
|
||||
endif()
|
||||
|
||||
# Add the BasicTypes unittest
|
||||
add_test(NAME UnitTest_CoreLoader COMMAND UnitTest_CoreLoader)
|
||||
|
||||
# Execute the test
|
||||
add_custom_command(TARGET UnitTest_CoreLoader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_CoreLoader>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_CoreLoader.xml
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# Build dependencies
|
||||
add_dependencies(UnitTest_CoreLoader_TestApp dependency_sdv_components)
|
||||
add_dependencies(UnitTest_CoreLoader_TestApp install_manifest)
|
||||
add_dependencies(UnitTest_CoreLoader UnitTest_CoreLoader_TestApp)
|
||||
357
tests/unit_tests/core_loader/core_loader_test.cpp
Normal file
357
tests/unit_tests/core_loader/core_loader_test.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <support/sdv_core.h>
|
||||
#include "../../../global/exec_dir_helper.h"
|
||||
#include <stdlib.h>
|
||||
#ifdef __unix__
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Helper class to store and restore the current state of various core library specific settings and to execute the test in
|
||||
* a specific subdirectory.
|
||||
* @remarks There is a difference between the usage of the path variable in Windows and in Posix. In Windows, environment'
|
||||
* variables being changed by the application are local to the application and are applied directly. In Posix, the ld.so
|
||||
* environment variables being changed by the application are only valid for any process starting after the change, but not for a
|
||||
* running process. Therefore the implementation under Posix would need to explicitly start the test in its own executable with the
|
||||
* variable changed.
|
||||
*/
|
||||
class CTestExecute
|
||||
{
|
||||
public:
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief The name of the test application to execute.
|
||||
*/
|
||||
static constexpr char szTestAppName[] = "UnitTest_CoreLoader_TestApp.exe";
|
||||
#else
|
||||
/**
|
||||
* @brief The name of the test application to execute.
|
||||
*/
|
||||
static constexpr char szTestAppName[] = "UnitTest_CoreLoader_TestApp";
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Test executor constructor
|
||||
* @details Create a specific test sub directory and copy the test applicatin into it. Store the current directory and move to
|
||||
* the location of the executable. Store the current PATH/LD_LIBRARY_PATH environment variable and reset the variable. Store
|
||||
* the current value of an existing SDV_FRAMEWORK_RUNTIME environment variable and remove the variable.
|
||||
*/
|
||||
CTestExecute()
|
||||
{
|
||||
// Get the timestring used for renaming files
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
std::stringstream sstreamTime;
|
||||
sstreamTime << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S");
|
||||
|
||||
// Create a test directory
|
||||
m_pathExeDir = GetExecDirectory() / (std::string("core_loader_test_") + sstreamTime.str());
|
||||
if (!std::filesystem::create_directory(m_pathExeDir)) return;
|
||||
|
||||
// Copy the test application
|
||||
std::filesystem::copy(GetExecDirectory() / szTestAppName, m_pathExeDir / szTestAppName);
|
||||
|
||||
// Store the current directory and move to the directory of the executable
|
||||
m_pathCurrentDir = std::filesystem::current_path();
|
||||
std::filesystem::current_path(m_pathExeDir);
|
||||
|
||||
// Store and remove the current PATH/LD_LIBRARY_PATH variable
|
||||
#ifdef _WIN32
|
||||
const wchar_t* szPath = _wgetenv(L"PATH");
|
||||
if (szPath) m_ssPath = szPath;
|
||||
// TODO: It could be that the path to the core lib is already available. Scan the path list and remove any to the core
|
||||
// lib. Reassign the path.
|
||||
// _wputenv(L"PATH=");
|
||||
#elif defined __unix__
|
||||
const char* szPath = getenv("LD_LIBRARY_PATH");
|
||||
if (szPath) m_ssPath = szPath;
|
||||
setenv("LD_LIBRARY_PATH", "", true);
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
|
||||
// Store and remove the current SDV_FRAMEWORK_RUNTIME variable
|
||||
#ifdef _WIN32
|
||||
const wchar_t* szFrameworkDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
|
||||
if (szFrameworkDir)
|
||||
{
|
||||
m_ssFrameworkDir = szFrameworkDir;
|
||||
_wputenv(L"SDV_FRAMEWORK_RUNTIME=");
|
||||
}
|
||||
#elif defined __unix__
|
||||
const char* szFrameworkDir = getenv("SDV_FRAMEWORK_RUNTIME");
|
||||
if (szFrameworkDir)
|
||||
{
|
||||
m_ssFrameworkDir = szFrameworkDir;
|
||||
unsetenv("SDV_FRAMEWORK_RUNTIME");
|
||||
}
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test executor destructor.
|
||||
* @details Return to the previous current-path location. Restore the previous PATH/LD_LIBRARY_PATH environment variable. If a
|
||||
* previous existing SDV_FRAMEWORK_RUNTIME environment variable was existing, restore this variable. Remove the test directory.
|
||||
*/
|
||||
~CTestExecute()
|
||||
{
|
||||
// Restore the current directory
|
||||
std::filesystem::current_path(m_pathCurrentDir);
|
||||
|
||||
// Delete the test directory
|
||||
if (!m_pathExeDir.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::remove_all(m_pathExeDir);
|
||||
} catch (const std::filesystem::filesystem_error&)
|
||||
{}
|
||||
}
|
||||
|
||||
// Restore the SDV_FRAMEWORK_RUNTIME variable
|
||||
if (!m_ssFrameworkDir.empty())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_wputenv((std::wstring(L"SDV_FRAMEWORK_RUNTIME=") + m_ssFrameworkDir).c_str());
|
||||
#elif defined __unix__
|
||||
setenv("SDV_FRAMEWORK_RUNTIME", m_ssFrameworkDir.c_str(), true);
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
// Restore the PATH/LD_LIBRARY_PATH variable
|
||||
#ifdef _WIN32
|
||||
_wputenv((std::wstring(L"PATH=") + m_ssPath).c_str());
|
||||
#elif defined __unix__
|
||||
setenv("LD_LIBRARY_PATH", m_ssPath.c_str(), true);
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run the test app process and check the result.
|
||||
* @return Returns a 1 when the test app process could run and provided a positive result. Returns 0 when the test app process
|
||||
* could run, but didn't provide a positive result. Returns -1 when the test app process couldn't run.
|
||||
*/
|
||||
int Execute()
|
||||
{
|
||||
// Start the process and wait for it to finish
|
||||
#ifdef _WIN32
|
||||
PROCESS_INFORMATION sProcessInfo{};
|
||||
STARTUPINFO sStartupInfo{};
|
||||
sStartupInfo.cb = sizeof(sStartupInfo);
|
||||
wchar_t szCommandLine[32768] = {};
|
||||
wcscpy(szCommandLine, (m_pathExeDir / szTestAppName).native().c_str());
|
||||
//wcscpy(szCommandLine, std::filesystem::path(szTestAppName).native().c_str());
|
||||
if (!CreateProcess(NULL, szCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &sStartupInfo, &sProcessInfo))
|
||||
{
|
||||
std::cerr << "Failed to create the test process... (" << GetLastError() << ")" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (WaitForSingleObject(sProcessInfo.hProcess, INFINITE) != WAIT_OBJECT_0)
|
||||
{
|
||||
std::cerr << "Process was not started..." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
DWORD dwExitCode = 0xffffffff;
|
||||
GetExitCodeProcess(sProcessInfo.hProcess, &dwExitCode);
|
||||
if (dwExitCode)
|
||||
{
|
||||
std::cerr << "Process exited with exit code: 0x" << std::hex << dwExitCode << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (sProcessInfo.hProcess) CloseHandle(sProcessInfo.hProcess);
|
||||
if (sProcessInfo.hThread) CloseHandle(sProcessInfo.hThread);
|
||||
#elif defined __unix__
|
||||
pid_t processID = 0;
|
||||
char* szArg = nullptr;
|
||||
int spawnResult = posix_spawn(&processID, (m_pathExeDir / szTestAppName).native().c_str(), nullptr, nullptr,
|
||||
&szArg, environ);
|
||||
if (spawnResult != 0) return -1;
|
||||
int status = 0;
|
||||
do
|
||||
{
|
||||
if (waitpid(processID, &status, WUNTRACED | WCONTINUED) == -1)
|
||||
return -1;
|
||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
|
||||
// Read the result from the result file
|
||||
bool bResult = false;
|
||||
std::ifstream fstream(m_pathExeDir / "CoreLoading_result.txt");
|
||||
if (!fstream.eof())
|
||||
fstream >> bResult;
|
||||
|
||||
// Done.
|
||||
return bResult ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add the core directory to the PATH/DL_LIBRARY_PATH environment variable.
|
||||
*/
|
||||
void AddCoreToSearchPath()
|
||||
{
|
||||
// Store and remove the current PATH/LD_LIBRARY_PATH variable
|
||||
#ifdef _WIN32
|
||||
std::wstringstream sstreamPath;
|
||||
sstreamPath << L"PATH=" << m_ssPath;
|
||||
if (!m_ssPath.empty())
|
||||
sstreamPath << L";";
|
||||
sstreamPath << (GetExecDirectory() / "../../bin").lexically_normal().native();
|
||||
_wputenv(sstreamPath.str().c_str());
|
||||
#elif defined __unix__
|
||||
setenv("LD_LIBRARY_PATH", (GetExecDirectory() / "../../bin").lexically_normal().native().c_str(), true);
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set framework environment variable.
|
||||
*/
|
||||
void SetFrameworkEnvVar()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_wputenv((std::wstring(L"SDV_FRAMEWORK_RUNTIME=") + (GetExecDirectory() / "../../bin").lexically_normal().native()).c_str());
|
||||
#elif defined __unix__
|
||||
setenv("SDV_FRAMEWORK_RUNTIME", (GetExecDirectory() / "../../bin").lexically_normal().native().c_str(), true);
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the location of the executable directory.
|
||||
* @return The executable directory path.
|
||||
*/
|
||||
std::filesystem::path GetExeDir() const
|
||||
{
|
||||
return m_pathExeDir;
|
||||
}
|
||||
|
||||
private:
|
||||
std::filesystem::path m_pathExeDir; ///< Execution path directory
|
||||
std::filesystem::path m_pathCurrentDir; ///< The current directory.
|
||||
#ifdef _WIN32
|
||||
std::wstring m_ssPath; ///< The current PATH environment variable before changing.
|
||||
std::wstring m_ssFrameworkDir; ///< The current SDV_FRAMEWORK_RUNTIME environment variable before changing.
|
||||
#elif __unix__
|
||||
std::string m_ssPath; ///< The current PATH environment variable before changing.
|
||||
std::string m_ssFrameworkDir; ///< The current SDV_FRAMEWORK_RUNTIME environment variable before changing.
|
||||
#else
|
||||
#error OS not supported!
|
||||
#endif
|
||||
};
|
||||
|
||||
TEST(CoreLoaderTest, FailedLoading)
|
||||
{
|
||||
CTestExecute executor;
|
||||
EXPECT_EQ(executor.Execute(), 0);
|
||||
}
|
||||
|
||||
TEST(CoreLoaderTest, SearchPathLoading)
|
||||
{
|
||||
CTestExecute executor;
|
||||
executor.AddCoreToSearchPath();
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
|
||||
TEST(CoreLoaderTest, EnvVarLoading)
|
||||
{
|
||||
CTestExecute executor;
|
||||
executor.SetFrameworkEnvVar();
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
|
||||
TEST(CoreLoaderTest, CfgFileLoadingRel)
|
||||
{
|
||||
CTestExecute executor;
|
||||
|
||||
std::ofstream fstream(executor.GetExeDir() / "sdv_core_reloc.toml");
|
||||
fstream << R"cfg(# Some bogus information
|
||||
unknown_var = 2
|
||||
|
||||
# Core library path
|
||||
directory = "../../../bin")cfg";
|
||||
fstream.close();
|
||||
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
|
||||
TEST(CoreLoaderTest, CfgFileLoadingAbs)
|
||||
{
|
||||
CTestExecute executor;
|
||||
|
||||
std::ofstream fstream(executor.GetExeDir() / "sdv_core_reloc.toml");
|
||||
fstream << R"cfg(# Some bogus information
|
||||
unknown_var = 2
|
||||
|
||||
# Core library path
|
||||
directory = ")cfg" << (executor.GetExeDir() / "../../../bin").lexically_normal().generic_string() << "\"";
|
||||
fstream.close();
|
||||
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST(CoreLoaderTest, CfgFileLoadingRelWin)
|
||||
{
|
||||
CTestExecute executor;
|
||||
|
||||
std::ofstream fstream(executor.GetExeDir() / "sdv_core_reloc.toml");
|
||||
fstream << R"cfg(# Some bogus information
|
||||
unknown_var = 2
|
||||
|
||||
# Core library path
|
||||
directory = "..\\..\\..\\bin")cfg";
|
||||
fstream.close();
|
||||
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
|
||||
TEST(CoreLoaderTest, CfgFileLoadingAbsWin)
|
||||
{
|
||||
CTestExecute executor;
|
||||
|
||||
// Convert UTF-16 to ANSI ignoring all non-convertable characters and add an escape character for each backslash
|
||||
auto fnSimpleMakeAnsi = [](const std::wstring& rss)
|
||||
{
|
||||
std::string ss;
|
||||
for (wchar_t c : rss)
|
||||
{
|
||||
if (c == '\\')
|
||||
ss.push_back(static_cast<char>(c));
|
||||
ss.push_back(static_cast<char>(c));
|
||||
}
|
||||
return ss;
|
||||
};
|
||||
|
||||
std::string ssDir = fnSimpleMakeAnsi((executor.GetExeDir() / "../../../bin").lexically_normal().native());
|
||||
|
||||
std::ofstream fstream(executor.GetExeDir() / "sdv_core_reloc.toml");
|
||||
fstream << R"cfg(# Some bogus information
|
||||
unknown_var = 2
|
||||
|
||||
# Core library path
|
||||
directory = ")cfg" << ssDir << "\"";
|
||||
fstream.close();
|
||||
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(CoreLoaderTest, IdenticalLocationLoading)
|
||||
{
|
||||
CTestExecute executor;
|
||||
|
||||
std::filesystem::copy(GetExecDirectory() / "../../bin/core_services.sdv", executor.GetExeDir() / "core_services.sdv");
|
||||
|
||||
EXPECT_EQ(executor.Execute(), 1);
|
||||
}
|
||||
14
tests/unit_tests/core_loader/main.cpp
Normal file
14
tests/unit_tests/core_loader/main.cpp
Normal 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();
|
||||
}
|
||||
20
tests/unit_tests/core_loader/test_app.cpp
Normal file
20
tests/unit_tests/core_loader/test_app.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <support/sdv_core.h>
|
||||
#include <stdlib.h>
|
||||
#include "../../../global/exec_dir_helper.h"
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain([[maybe_unused]] int argc, [[maybe_unused]] wchar_t* argv[])
|
||||
#else
|
||||
extern "C" int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
|
||||
#endif
|
||||
{
|
||||
sdv::core::internal::CSDVCoreLoader loader;
|
||||
bool bResult = !static_cast<sdv::TInterfaceAccessPtr>(loader) ? true : false;
|
||||
std::cout << "Child process before loading: core interface availability: " << (bResult ? "not available" : "available") << std::endl;
|
||||
loader.Load();
|
||||
bResult &= static_cast<sdv::TInterfaceAccessPtr>(loader) ? true : false;
|
||||
std::ofstream fstream(GetExecDirectory() / "CoreLoading_result.txt");
|
||||
fstream << bResult;
|
||||
std::cout << "Child process after loading: core interface availability: " << (bResult ? "available" : "not available") << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user