* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
* ubs-engine is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "test_ubse_context.h"
#include <linux/limits.h>
#include <unistd.h>
#include <filesystem>
#include <mockcpp/mockcpp.hpp>
#include "ubse_error.h"
#include "ubse_module.h"
namespace ubse::ut::context {
using namespace ubse::context;
using namespace ubse::module;
using testing::_;
using testing::Return;
const int ARGC = 3;
const std::string ARG_NAME = "f";
const std::string ARG_VAL = "conf";
const std::string DASH_ARG_NAME = "-" + ARG_NAME;
char* g_argv[] = {(char*)"", (char*)DASH_ARG_NAME.c_str(), (char*)ARG_VAL.c_str()};
std::string GetRealRunPath()
{
char buf[PATH_MAX] = {0};
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (len > 0) {
buf[len] = '\0';
std::filesystem::path exePath(buf);
return exePath.parent_path().string();
}
return "/tmp";
}
void StubGetExecutablePath(UbseContext& ctx)
{
ctx.ubseRunPath_ = GetRealRunPath();
MOCKER(&UbseContext::GetExecutablePath).stubs().will(returnValue(UBSE_OK));
}
void ResetGetExecutablePathStub()
{
GlobalMockObject::reset();
}
TEST_F(TestUbseContext, EMPTYMODULES)
{
context.moduleCreatorMap_.clear();
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_OK);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, CyclicDependencyModule)
{
context.RegisterModule<MockUbseModule, MockUbseModuleD>(UbseModule::CreateModule<MockUbseModule>);
context.RegisterModule<MockUbseModuleD, MockUbseModule>(UbseModule::CreateModule<MockUbseModuleD>);
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_ERROR_MODULE_LOAD_FAILED);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, ModuleNotRegisteredError)
{
context.RegisterModule<MockUbseModule, MockUbseModuleD>(UbseModule::CreateModule<MockUbseModule>);
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_ERROR_MODULE_LOAD_FAILED);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, RegisterArgError)
{
context.CreateModules();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, RegArgs()).WillOnce([]() { throw std::runtime_error(""); });
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_ERROR_PARSE_ARGS_FAILED);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, ParserArgsError)
{
char empty[3] = "";
char* errArgv[] = {empty, const_cast<char*>(ARG_NAME.c_str()), const_cast<char*>(ARG_VAL.c_str())};
context.CreateModules();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, RegArgs()).WillRepeatedly(Return());
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, errArgv, ProcessMode::MANAGER), UBSE_ERROR_PARSE_ARGS_FAILED);
ResetGetExecutablePathStub();
context.processMode_ = ProcessMode::DEFAULT;
context.argMap_.clear();
context.allModulesReady_.store(false);
char tmp[2] = "-";
errArgv[1] = tmp;
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, errArgv, ProcessMode::MANAGER), UBSE_ERROR_PARSE_ARGS_FAILED);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, InitModuleError)
{
context.CreateModules();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, Initialize()).WillOnce(Return(UBSE_ERROR));
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_ERROR);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, StartModuleError)
{
context.CreateModules();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, Initialize()).WillRepeatedly(Return(UBSE_OK));
EXPECT_CALL(*module, Start()).WillOnce(Return(UBSE_ERROR));
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_ERROR);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, RunAllSuccess)
{
context.CreateModules();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, Start()).WillRepeatedly(Return(UBSE_OK));
StubGetExecutablePath(context);
EXPECT_EQ(context.Run(ARGC, g_argv, ProcessMode::MANAGER), UBSE_OK);
ResetGetExecutablePathStub();
}
TEST_F(TestUbseContext, StopModuleError)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, Stop()).WillOnce([]() { throw std::runtime_error("stop error"); });
EXPECT_NO_THROW(context.Stop());
}
TEST_F(TestUbseContext, DestroyModuleError)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, Stop()).WillRepeatedly(Return());
EXPECT_CALL(*module, UnInitialize()).WillOnce([]() { throw std::runtime_error("destroy error"); });
EXPECT_NO_THROW(context.Stop());
}
TEST_F(TestUbseContext, DestroyModuleSuccess)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv);
ResetGetExecutablePathStub();
auto module = context.GetModule<MockUbseModule>().get();
EXPECT_CALL(*module, Stop()).WillRepeatedly(Return());
EXPECT_NO_THROW(context.Stop());
}
TEST_F(TestUbseContext, GetModuleFailed)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
EXPECT_EQ(context.GetModule<MockUbseModuleD>(), nullptr);
}
TEST_F(TestUbseContext, GetModuleSuccess)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
EXPECT_EQ(context.GetModule<MockUbseModule>(), context.moduleMap_[typeid(MockUbseModule)]);
}
TEST_F(TestUbseContext, GetArgStrFailed)
{
std::string noArgName = "noArgs";
std::string noArgValue;
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
EXPECT_EQ(context.GetArgStr(noArgName, noArgValue), UBSE_ERROR_PARSE_ARGS_FAILED);
}
TEST_F(TestUbseContext, GetArgStrSuccess)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
std::string getArgValue;
EXPECT_EQ(context.GetArgStr(ARG_NAME, getArgValue), UBSE_OK);
EXPECT_STREQ(getArgValue.c_str(), ARG_VAL.c_str());
}
TEST_F(TestUbseContext, GetProcessDefaultMode)
{
EXPECT_EQ(context.GetProcessMode(), ProcessMode::MANAGER);
}
TEST_F(TestUbseContext, GetProcessMode)
{
StubGetExecutablePath(context);
context.Run(ARGC, g_argv, ProcessMode::MANAGER);
ResetGetExecutablePathStub();
EXPECT_EQ(context.GetProcessMode(), ProcessMode::MANAGER);
}
TEST_F(TestUbseContext, GetExecutablePathSuccess)
{
UbseResult ret = context.GetExecutablePath();
if (ret == UBSE_OK) {
std::string expectedPath = GetRealRunPath();
EXPECT_EQ(context.GetUbseRunPath(), expectedPath);
} else {
EXPECT_EQ(ret, UBSE_ERROR);
}
}
TEST_F(TestUbseContext, GetExecutablePathUbseRunPath)
{
UbseResult ret = context.GetExecutablePath();
if (ret == UBSE_OK) {
EXPECT_FALSE(context.GetUbseRunPath().empty());
EXPECT_NE(context.GetUbseRunPath().find("cmake-build"), std::string::npos);
}
}
void TestUbseContext::SetUp()
{
g_globalStop.store(false);
context.moduleCreatorMap_.clear();
context.baseModuleCreatorMap_.clear();
context.moduleMap_.clear();
context.sortedModules_.clear();
context.sortedBaseModules_.clear();
context.argMap_.clear();
context.processMode_ = ProcessMode::DEFAULT;
context.allModulesReady_.store(false);
context.ubseRunPath_.clear();
context.cmdArgc_ = 0;
context.cmdArgv_ = nullptr;
context.RegisterModule<MockUbseModule>(UbseModule::CreateModule<MockUbseModule>);
Test::SetUp();
}
void TestUbseContext::TearDown()
{
g_globalStop.store(false);
context.moduleCreatorMap_.clear();
context.baseModuleCreatorMap_.clear();
context.moduleMap_.clear();
context.sortedModules_.clear();
context.sortedBaseModules_.clear();
context.argMap_.clear();
context.processMode_ = ProcessMode::DEFAULT;
context.allModulesReady_.store(false);
context.ubseRunPath_.clear();
context.cmdArgc_ = 0;
context.cmdArgv_ = nullptr;
Test::TearDown();
}
}