aboutsummaryrefslogtreecommitdiff
path: root/zenutil/zenserverprocess.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-08-06 17:02:17 +0200
committerStefan Boberg <[email protected]>2021-08-06 17:03:47 +0200
commit4d70af00d66cbfbd9f52afdfce7bcb4ec1881121 (patch)
tree95108f43f576adceb6cd394238ae6caca74a711d /zenutil/zenserverprocess.cpp
parentzen::Process -> zen::ProcessHandle (diff)
downloadzen-4d70af00d66cbfbd9f52afdfce7bcb4ec1881121.tar.xz
zen-4d70af00d66cbfbd9f52afdfce7bcb4ec1881121.zip
Repurposing test utility code to enable server control via zen
Diffstat (limited to 'zenutil/zenserverprocess.cpp')
-rw-r--r--zenutil/zenserverprocess.cpp173
1 files changed, 173 insertions, 0 deletions
diff --git a/zenutil/zenserverprocess.cpp b/zenutil/zenserverprocess.cpp
new file mode 100644
index 000000000..f58a9f166
--- /dev/null
+++ b/zenutil/zenserverprocess.cpp
@@ -0,0 +1,173 @@
+// 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};
+
+ZenServerEnvironment::ZenServerEnvironment()
+{
+}
+
+ZenServerEnvironment::~ZenServerEnvironment()
+{
+}
+
+void
+ZenServerEnvironment::Initialize(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir)
+{
+ m_ProgramBaseDir = ProgramBaseDir;
+ m_TestBaseDir = TestBaseDir;
+
+ spdlog::info("Program base dir is '{}'", ProgramBaseDir);
+ spdlog::info("Cleaning test base dir '{}'", TestBaseDir);
+ zen::DeleteDirectories(TestBaseDir.c_str());
+
+ m_IsInitialized = true;
+}
+
+std::filesystem::path
+ZenServerEnvironment::CreateNewTestDir()
+{
+ using namespace std::literals;
+
+ zen::ExtendableWideStringBuilder<256> TestDir;
+ TestDir << "test"sv << int64_t(++TestCounter);
+
+ std::filesystem::path TestPath = m_TestBaseDir / TestDir.c_str();
+
+ spdlog::info("Creating new test dir @ '{}'", TestPath);
+
+ zen::CreateDirectories(TestPath.c_str());
+
+ return TestPath;
+}
+
+std::filesystem::path
+ZenServerEnvironment::RootDir(std::string_view Path)
+{
+ std::filesystem::path Root = m_ProgramBaseDir.parent_path().parent_path();
+
+ std::filesystem::path Relative{Path};
+
+ return Root / Relative;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+std::atomic<int> ChildIdCounter{0};
+
+ZenServerInstance::ZenServerInstance(ZenServerEnvironment& 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();
+ }
+
+ if (m_MeshEnabled)
+ {
+ CommandLine << " --mesh";
+ }
+
+ 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);
+}