diff options
Diffstat (limited to 'zentestutil')
| -rw-r--r-- | zentestutil/include/zenserverprocess.h | 53 | ||||
| -rw-r--r-- | zentestutil/zenserverprocess.cpp | 155 | ||||
| -rw-r--r-- | zentestutil/zentestutil.vcxproj | 104 | ||||
| -rw-r--r-- | zentestutil/zentestutil.vcxproj.filters | 9 |
4 files changed, 321 insertions, 0 deletions
diff --git a/zentestutil/include/zenserverprocess.h b/zentestutil/include/zenserverprocess.h new file mode 100644 index 000000000..3f86f283c --- /dev/null +++ b/zentestutil/include/zenserverprocess.h @@ -0,0 +1,53 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zencore/thread.h> + +#include <spdlog/spdlog.h> + +#include <filesystem> + +class ZenTestEnvironment +{ +public: + ZenTestEnvironment(); + ~ZenTestEnvironment(); + + void Initialize(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir); + + std::filesystem::path CreateNewTestDir(); + std::filesystem::path ProgramBaseDir() const { return m_ProgramBaseDir; } + bool IsInitialized() const { return m_IsInitialized; } + +private: + std::filesystem::path m_ProgramBaseDir; + std::filesystem::path m_TestBaseDir; + bool m_IsInitialized = false; +}; + +struct ZenServerInstance +{ + ZenServerInstance(ZenTestEnvironment& TestEnvironment); + ~ZenServerInstance(); + + void SignalShutdown() { m_ShutdownEvent.Set(); } + void WaitUntilReady() { m_ReadyEvent.Wait(); } + void EnableTermination() { m_Terminate = true; } + + void SetTestDir(std::filesystem::path TestDir) + { + ZEN_ASSERT(!m_Process.IsValid()); + m_TestDir = TestDir; + } + + void SpawnServer(int BasePort); + +private: + ZenTestEnvironment& m_Env; + zen::Process m_Process; + zen::Event m_ReadyEvent; + zen::Event m_ShutdownEvent; + bool m_Terminate = false; + std::filesystem::path m_TestDir; +}; diff --git a/zentestutil/zenserverprocess.cpp b/zentestutil/zenserverprocess.cpp new file mode 100644 index 000000000..9d62d692f --- /dev/null +++ b/zentestutil/zenserverprocess.cpp @@ -0,0 +1,155 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "zenserverprocess.h" + +#include <zencore/filesystem.h> +#include <zencore/fmtutils.h> +#include <zencore/string.h> + +#include <spdlog/spdlog.h> + +////////////////////////////////////////////////////////////////////////// + +std::atomic<int> TestCounter{0}; + +ZenTestEnvironment::ZenTestEnvironment() +{ +} + +ZenTestEnvironment::~ZenTestEnvironment() +{ +} + +void +ZenTestEnvironment::Initialize(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir) +{ + m_ProgramBaseDir = ProgramBaseDir; + m_TestBaseDir = TestBaseDir; + + spdlog::info("Cleaning '{}'", TestBaseDir); + zen::DeleteDirectories(TestBaseDir.c_str()); + + m_IsInitialized = true; +} + +std::filesystem::path +ZenTestEnvironment::CreateNewTestDir() +{ + using namespace std::literals; + + zen::ExtendableWideStringBuilder<256> TestDir; + TestDir << "test"sv << int64_t(++TestCounter); + + std::filesystem::path TestPath = m_TestBaseDir / TestDir.c_str(); + + zen::CreateDirectories(TestPath.c_str()); + + return TestPath; +} + +////////////////////////////////////////////////////////////////////////// + +std::atomic<int> ChildIdCounter{0}; + +ZenServerInstance::ZenServerInstance(ZenTestEnvironment& TestEnvironment) : m_Env(TestEnvironment) +{ + ZEN_ASSERT(TestEnvironment.IsInitialized()); +} + +ZenServerInstance::~ZenServerInstance() +{ + if (m_Process.IsValid()) + { + if (m_Terminate) + { + spdlog::info("Terminating zenserver process"); + m_Process.Terminate(111); + } + else + { + SignalShutdown(); + m_Process.Wait(); + } + } +} + +void +ZenServerInstance::SpawnServer(int BasePort) +{ + ZEN_ASSERT(!m_Process.IsValid()); // Only spawn once + + const std::filesystem::path BaseDir = m_Env.ProgramBaseDir(); + const std::filesystem::path Executable = BaseDir / "zenserver.exe"; + + const int MyPid = _getpid(); + const int ChildId = ++ChildIdCounter; + + zen::ExtendableStringBuilder<32> ChildEventName; + ChildEventName << "Zen_Child_" << ChildId; + zen::NamedEvent ChildEvent{ChildEventName}; + + zen::ExtendableStringBuilder<32> ChildShutdownEventName; + ChildShutdownEventName << "Zen_Child_" << ChildId; + ChildShutdownEventName << "_Shutdown"; + zen::NamedEvent ChildShutdownEvent{ChildShutdownEventName}; + + zen::ExtendableStringBuilder<32> LogId; + LogId << "Zen" << ChildId; + + zen::ExtendableWideStringBuilder<128> CommandLine; + CommandLine << "\""; + CommandLine.Append(Executable.c_str()); + CommandLine << "\" --test --owner-pid "; + CommandLine << MyPid; + CommandLine << " "; + CommandLine << "--port " << BasePort; + CommandLine << " --child-id " << ChildEventName; + CommandLine << " --log-id " << LogId; + + if (!m_TestDir.empty()) + { + CommandLine << " --data-dir "; + CommandLine << m_TestDir.c_str(); + } + + std::filesystem::path CurrentDirectory = std::filesystem::current_path(); + + spdlog::debug("Spawning server"); + + PROCESS_INFORMATION ProcessInfo{}; + STARTUPINFO Sinfo{.cb = sizeof(STARTUPINFO)}; + + DWORD CreationFlags = 0; // CREATE_NEW_CONSOLE; + const bool InheritHandles = false; + void* Environment = nullptr; + LPSECURITY_ATTRIBUTES ProcessAttributes = nullptr; + LPSECURITY_ATTRIBUTES ThreadAttributes = nullptr; + + BOOL Success = CreateProcessW(Executable.c_str(), + (LPWSTR)CommandLine.c_str(), + ProcessAttributes, + ThreadAttributes, + InheritHandles, + CreationFlags, + Environment, + CurrentDirectory.c_str(), + &Sinfo, + &ProcessInfo); + + if (Success == FALSE) + { + std::error_code err(::GetLastError(), std::system_category()); + + spdlog::error("Server spawn failed: {}", err.message()); + + throw std::system_error(err, "failed to create server process"); + } + + spdlog::debug("Server spawned OK"); + + CloseHandle(ProcessInfo.hThread); + + m_Process.Initialize(ProcessInfo.hProcess); + m_ReadyEvent = std::move(ChildEvent); + m_ShutdownEvent = std::move(ChildShutdownEvent); +} diff --git a/zentestutil/zentestutil.vcxproj b/zentestutil/zentestutil.vcxproj new file mode 100644 index 000000000..8213763fc --- /dev/null +++ b/zentestutil/zentestutil.vcxproj @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <ProjectGuid>{77f8315d-b21d-4db0-9a6f-2d3359f88a70}</ProjectGuid> + <RootNamespace>zentestutil</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\zen_base_debug.props" /> + <Import Project="..\zenfs_common.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\zen_base_release.props" /> + <Import Project="..\zenfs_common.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnableManifest>true</VcpkgEnableManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgUseStatic>true</VcpkgUseStatic> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <VcpkgUseStatic>true</VcpkgUseStatic> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\zencore\include;..\zenstore\include;.\include</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\zencore\include;..\zenstore\include;.\include</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="zenserverprocess.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="zenserverprocess.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/zentestutil/zentestutil.vcxproj.filters b/zentestutil/zentestutil.vcxproj.filters new file mode 100644 index 000000000..1afefcdf7 --- /dev/null +++ b/zentestutil/zentestutil.vcxproj.filters @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="zenserverprocess.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="zenserverprocess.h" /> + </ItemGroup> +</Project>
\ No newline at end of file |