Files
MobileGL/MobileGL/MG_Test/Util/ConfigFileTest.cpp
T

177 lines
7.3 KiB
C++

// MobileGL - MobileGL/MG_Test/Util/ConfigFileTest.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
// The system configuration files (ConfigLoader.cpp): environment > backend file > client.conf >
// built-in default, for MG_ConfigLoader::Init() and for the LookupSetting readers that run before
// it. No GL context, no driver: the loader is parsing.
#include <gtest/gtest.h>
#include <Config.h>
#include <Init.h>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <string>
#include <tuple>
#include <vector>
#include <unistd.h>
namespace {
using MobileGL::BackendType;
using MobileGL::String;
namespace Config = MobileGL::MG_Config;
namespace Loader = MobileGL::MG_ConfigLoader;
// Every variable a case touches, restored after it.
constexpr const char* kTouched[] = {
"MOBILEGL_CONFIG_FILE", "MOBILEGL_BACKEND_FILE", "MOBILEGL_BACKEND_TYPE",
"MOBILEGL_MAGMA_FRAMESINFLIGHT", "MOBILEGL_TRANSPORT", "MOBILEGL_IPC_CONTROL",
"MOBILEGL_IPC_DATA", "MOBILEGL_IPC_ROLE", "MOBILEGL_TEST_ONLY_KEY",
};
class ConfigFileTest : public ::testing::Test {
protected:
void SetUp() override {
for (const char* name : kTouched) {
const char* value = std::getenv(name);
saved_.emplace_back(name, value != nullptr, value != nullptr ? value : "");
::unsetenv(name);
}
dir_ = std::filesystem::temp_directory_path() /
("mgl-config-test-" + std::to_string(::getpid()) + "-" +
::testing::UnitTest::GetInstance()->current_test_info()->name());
std::filesystem::create_directories(dir_);
conf_ = (dir_ / "client.conf").string();
backend_ = (dir_ / "backend").string();
// Point both at this case's files, which do not exist yet: the host's own /etc is
// never read by a case.
::setenv("MOBILEGL_CONFIG_FILE", conf_.c_str(), 1);
::setenv("MOBILEGL_BACKEND_FILE", backend_.c_str(), 1);
}
void TearDown() override {
for (const auto& [name, had, value] : saved_) {
if (had) ::setenv(name.c_str(), value.c_str(), 1);
else ::unsetenv(name.c_str());
}
std::error_code ec;
std::filesystem::remove_all(dir_, ec);
Loader::Init(); // leave the process's configuration as its environment says
}
static void Write(const std::string& path, const std::string& text) {
std::ofstream out(path, std::ios::binary);
out << text;
}
static String Lookup(const char* key) {
String value;
return Loader::LookupSetting(key, value) ? value : String("<unset>");
}
std::vector<std::tuple<std::string, bool, std::string>> saved_;
std::filesystem::path dir_;
std::string conf_;
std::string backend_;
};
TEST_F(ConfigFileTest, WithoutFilesOrEnvironmentTheBuiltInDefaultsHold) {
Loader::Init();
EXPECT_EQ(Config::ActiveBackendType, BackendType::DirectGLES);
EXPECT_EQ(Config::Features.MagmaFramesInFlight, 3u);
EXPECT_EQ(Lookup("MOBILEGL_TRANSPORT"), "<unset>");
#if MOBILEGL_BUILD_DISAGGREGATED
EXPECT_EQ(Config::Transport, Config::TransportMode::Monolith);
EXPECT_EQ(Config::Ipc.Control, "fork");
#endif
}
TEST_F(ConfigFileTest, TheFileFillsWhatTheEnvironmentLeavesUnset) {
Write(conf_, "# a comment\n"
"\n"
" MOBILEGL_MAGMA_FRAMESINFLIGHT = 5 \n"
"MOBILEGL_TRANSPORT=spawn\r\n"
"MOBILEGL_IPC_CONTROL=\"unix:@test-endpoint\"\n"
"MOBILEGL_IPC_DATA='shm'\n"
"NOT_OURS=1\n"
"garbage line without equals\n"
"MOBILEGL_TEST_ONLY_KEY=a=b\n");
Loader::Init();
EXPECT_EQ(Config::Features.MagmaFramesInFlight, 5u);
EXPECT_EQ(Lookup("MOBILEGL_TRANSPORT"), "spawn");
EXPECT_EQ(Lookup("MOBILEGL_IPC_CONTROL"), "unix:@test-endpoint");
EXPECT_EQ(Lookup("MOBILEGL_IPC_DATA"), "shm");
EXPECT_EQ(Lookup("MOBILEGL_TEST_ONLY_KEY"), "a=b"); // only the first '=' splits
EXPECT_EQ(Lookup("NOT_OURS"), "<unset>");
#if MOBILEGL_BUILD_DISAGGREGATED
EXPECT_EQ(Config::Transport, Config::TransportMode::Spawn);
EXPECT_EQ(Config::Ipc.Control, "unix:@test-endpoint");
EXPECT_EQ(Config::Ipc.Data, "shm");
#endif
}
TEST_F(ConfigFileTest, TheEnvironmentWinsOverTheFile) {
Write(conf_, "MOBILEGL_MAGMA_FRAMESINFLIGHT=5\nMOBILEGL_IPC_CONTROL=unix:@from-file\n");
::setenv("MOBILEGL_MAGMA_FRAMESINFLIGHT", "7", 1);
::setenv("MOBILEGL_IPC_CONTROL", "unix:@from-env", 1);
Loader::Init();
EXPECT_EQ(Config::Features.MagmaFramesInFlight, 7u);
EXPECT_EQ(Lookup("MOBILEGL_IPC_CONTROL"), "unix:@from-env");
#if MOBILEGL_BUILD_DISAGGREGATED
EXPECT_EQ(Config::Ipc.Control, "unix:@from-env");
#endif
// Set but empty is still the environment speaking.
::setenv("MOBILEGL_IPC_CONTROL", "", 1);
EXPECT_EQ(Lookup("MOBILEGL_IPC_CONTROL"), "");
}
TEST_F(ConfigFileTest, TheBackendFileNamesTheBackendUnderTheEnvironmentAndOverClientConf) {
Write(backend_, " DirectVulkan \n");
Write(conf_, "MOBILEGL_BACKEND_TYPE=DirectGLES\n");
Loader::Init();
EXPECT_EQ(Config::ActiveBackendType, BackendType::DirectVulkan);
EXPECT_EQ(Lookup("MOBILEGL_BACKEND_TYPE"), "DirectVulkan");
::setenv("MOBILEGL_BACKEND_TYPE", "DirectGLES", 1);
Loader::Init();
EXPECT_EQ(Config::ActiveBackendType, BackendType::DirectGLES);
::unsetenv("MOBILEGL_BACKEND_TYPE");
// Without the backend file, client.conf's line is the answer.
std::filesystem::remove(backend_);
Write(conf_, "MOBILEGL_BACKEND_TYPE=DirectVulkan\n");
Loader::Init();
EXPECT_EQ(Config::ActiveBackendType, BackendType::DirectVulkan);
}
TEST_F(ConfigFileTest, AnEmptyPathTurnsAFileOffAndAMissingFileIsNoError) {
Write(conf_, "MOBILEGL_MAGMA_FRAMESINFLIGHT=5\n");
Write(backend_, "DirectVulkan\n");
::setenv("MOBILEGL_CONFIG_FILE", "", 1);
::setenv("MOBILEGL_BACKEND_FILE", "", 1);
Loader::Init();
EXPECT_EQ(Config::Features.MagmaFramesInFlight, 3u);
EXPECT_EQ(Config::ActiveBackendType, BackendType::DirectGLES);
::setenv("MOBILEGL_CONFIG_FILE", (dir_ / "absent.conf").string().c_str(), 1);
Loader::Init();
EXPECT_EQ(Config::Features.MagmaFramesInFlight, 3u);
}
TEST_F(ConfigFileTest, AServerProcessNeverReadsTheClientsFile) {
Write(conf_, "MOBILEGL_MAGMA_FRAMESINFLIGHT=5\n");
Write(backend_, "DirectVulkan\n");
::setenv("MOBILEGL_IPC_ROLE", "server", 1);
Loader::Init();
EXPECT_EQ(Config::Features.MagmaFramesInFlight, 3u);
EXPECT_EQ(Config::ActiveBackendType, BackendType::DirectGLES);
EXPECT_EQ(Lookup("MOBILEGL_MAGMA_FRAMESINFLIGHT"), "<unset>");
}
} // namespace