* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "runtime_manager/log/log_manager.h"
#include <fcntl.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <fstream>
#include <regex>
#include "common/logs/logging.h"
#include "runtime_manager/manager/runtime_manager_test_actor.h"
#include "utils/future_test_helper.h"
#include "utils/generate_info.h"
#include "utils/os_utils.hpp"
namespace functionsystem::test {
using namespace functionsystem::runtime_manager;
using namespace ::testing;
namespace {
const std::string LOG_BASE_DIR = "/tmp/snuser/log/";
const std::string LOG_NAME = "dggphis151702";
const std::string EXCEPTION_LOG_DIR = "/tmp/snuser/log/exception/";
const std::string STD_LOG_DIR = "/tmp/snuser/log/instances/";
}
class LogManagerActorHelper : public runtime_manager::LogManagerActor {
public:
explicit LogManagerActorHelper(const std::string &name, const litebus::AID &runtimeManagerAID,
bool logReuse = false)
: LogManagerActor(name, runtimeManagerAID, logReuse) {};
MOCK_METHOD(litebus::Future<bool>, IsRuntimeActive, (const std::string &runtimeID), (const));
MOCK_METHOD(litebus::Future<bool>, IsRuntimeActiveByPid, (const pid_t &pid), (const));
};
class LogManagerTest : public testing::Test {
public:
void MockCreateJavaRuntimeLogs()
{
javaRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
auto javaLogDir = litebus::os::Join(LOG_BASE_DIR, javaRuntimeID_);
(void)litebus::os::Mkdir(javaLogDir);
auto javaRuntimeErrorLog = "java-runtime-error.log";
auto javaRuntimeErrorLogFile = litebus::os::Join(javaLogDir, javaRuntimeErrorLog);
auto fd = open(javaRuntimeErrorLogFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(javaRuntimeErrorLogFile.c_str());
outfile << "java runtime error log. This is a Test." << std::endl;
outfile.close();
auto javaRuntimeWarnLog = "java-runtime-warn.log";
auto javaRuntimeWarnLogFile = litebus::os::Join(javaLogDir, javaRuntimeWarnLog);
fd = open(javaRuntimeWarnLogFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
outfile.open(javaRuntimeWarnLogFile.c_str());
outfile << "java runtime warn log. This is a Test." << std::endl;
outfile.close();
auto javaRuntimeAllLog = "java-runtime-all.log";
auto javaRuntimeAllLogFile = litebus::os::Join(javaLogDir, javaRuntimeAllLog);
fd = open(javaRuntimeAllLogFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
outfile.open(javaRuntimeAllLogFile.c_str());
outfile << "java runtime all log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateCppRuntimeLogs()
{
auto jobId = litebus::uuid_generator::UUID::GetRandomUUID().ToString().substr(0, 8);
cppRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
auto cppLogFile = litebus::os::Join(LOG_BASE_DIR, jobId + "-" + cppRuntimeID_ + ".log");
int fd = open(cppLogFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(cppLogFile.c_str());
outfile << "cpp runtime log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateCppRuntimeLogs2()
{
auto jobId = "cpp-runtime_" + litebus::uuid_generator::UUID::GetRandomUUID().ToString().substr(0, 8) + "_";
cppRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
auto cppLogFile = litebus::os::Join(LOG_BASE_DIR, jobId + cppRuntimeID_ + ".log.gz");
int fd = open(cppLogFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(cppLogFile.c_str());
outfile << "cpp runtime log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateLibRuntimeLogs()
{
(void)litebus::os::Mkdir(LOG_BASE_DIR);
auto jobId = "job-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString().substr(0, 8);
libRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
auto logFile = litebus::os::Join(LOG_BASE_DIR, jobId + "-" + libRuntimeID_ + ".log");
int fd = open(logFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(logFile.c_str());
outfile << "cpp runtime log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateDsClientLogs()
{
std::vector<std::string> logFiles = {
"ds_client_12345.DEBUG",
"ds_client_12345.DEBUG.log",
"ds_client_12345.INFO",
"ds_client_12345.INFO.log",
"ds_client_12345.WARNING",
"ds_client_12345.WARNING.log",
"ds_client_12345.ERROR",
"ds_client_12345.ERROR.log",
"ds_client_access_12345.log"
};
(void)litebus::os::Mkdir(LOG_BASE_DIR);
for (const auto& logFile : logFiles) {
auto logPath = litebus::os::Join(LOG_BASE_DIR, logFile);
auto fd = open(logPath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(logPath.c_str());
outfile << logPath << " This is a Test." << std::endl;
outfile.close();
}
}
void MockCreateCppRuntimeRollingLogsWithCompression()
{
auto jobId = litebus::uuid_generator::UUID::GetRandomUUID().ToString().substr(0, 8);
cppRollingCompressionRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
for (int i = 10; i >= 1; --i) {
std::stringstream logFileName;
auto cppLogFile = litebus::os::Join(LOG_BASE_DIR, jobId + "-" + cppRollingCompressionRuntimeID_);
if (i == 1) {
logFileName << cppLogFile << ".log";
} else {
logFileName << cppLogFile << "." << (i - 1) << ".log.gz";
}
YRLOG_DEBUG("Creating log files for: {}", cppLogFile);
std::ofstream outfile(logFileName.str());
outfile << "cpp runtime log #" << i << ". This is a Test." << std::endl;
outfile.close();
YRLOG_DEBUG("Created: {}", logFileName.str());
}
YRLOG_DEBUG("Finished creating log files.");
}
void MockCreatePythonRuntimeRollingLogs()
{
pythonRollingRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
for (int i = 10; i >= 1; --i) {
std::stringstream logFileName;
std::string cppLogFile = litebus::os::Join(LOG_BASE_DIR, cppRollingRuntimeID_);
if (i == 1) {
logFileName << cppLogFile << ".log";
} else {
logFileName << cppLogFile << ".log" << "." << (i - 1);
}
YRLOG_DEBUG("Creating log files for: {}", cppLogFile);
std::ofstream outfile(logFileName.str());
outfile << "cpp runtime log #" << i << ". This is a Test." << std::endl;
outfile.close();
YRLOG_DEBUG("Created: {}", logFileName.str());
}
YRLOG_DEBUG("Finished creating log files.");
}
void MockCreateCppRuntimeRollingLogs()
{
auto jobId = litebus::uuid_generator::UUID::GetRandomUUID().ToString().substr(0, 8);
cppRollingRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
for (int i = 10; i >= 1; --i) {
std::stringstream logFileName;
std::string cppLogFile = litebus::os::Join(LOG_BASE_DIR, jobId + "-" + cppRollingRuntimeID_);
if (i == 1) {
logFileName << cppLogFile << ".log";
} else {
logFileName << cppLogFile << "." << (i - 1) << ".log";
}
YRLOG_DEBUG("Creating log files for: {}", cppLogFile);
std::ofstream outfile(logFileName.str());
outfile << "cpp runtime log #" << i << ". This is a Test." << std::endl;
outfile.close();
YRLOG_DEBUG("Created: {}", logFileName.str());
}
YRLOG_DEBUG("Finished creating log files.");
}
void MockCreatePythonRuntimeLogs()
{
pythonRuntimeID_ = "runtime-" + litebus::uuid_generator::UUID::GetRandomUUID().ToString();
auto pythonLogFile = litebus::os::Join(LOG_BASE_DIR, pythonRuntimeID_ + ".log");
int fd = open(pythonLogFile.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(pythonLogFile.c_str());
outfile << "python runtime log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateExceptionLogs()
{
litebus::os::Mkdir(EXCEPTION_LOG_DIR);
const std::string &runtimeBackTraceLog = EXCEPTION_LOG_DIR + "/BackTrace_runtime-ID.log";
auto fd = open(runtimeBackTraceLog.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(runtimeBackTraceLog.c_str());
outfile << "runtime ID backtrace log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateRuntimeStdLogs()
{
if (!litebus::os::ExistPath(STD_LOG_DIR)) {
litebus::os::Mkdir(STD_LOG_DIR);
}
const std::string &runtimeStdLog = STD_LOG_DIR + LOG_NAME + "-user_func_std.log";
auto fd = open(runtimeStdLog.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(runtimeStdLog.c_str());
outfile << "runtime ID Std log. This is a Test." << std::endl;
outfile.close();
}
void MockCreateLogs()
{
MockCreateJavaRuntimeLogs();
MockCreateCppRuntimeLogs();
MockCreatePythonRuntimeLogs();
MockCreateExceptionLogs();
MockCreateRuntimeStdLogs();
}
void MockCreatePrefixLogs()
{
(void)litebus::os::Mkdir(LOG_BASE_DIR);
std::vector<std::string> logNameList = {
"YR_123_000001_abc_libruntime.log",
"YR_123_000001_abc_libruntime.2025081617281825.log",
"YR_123_000001_abc_libruntime.2025081801463525.log.gz",
"YR_123_000001_abc_libruntime.2025082901463525.log.gz.1",
"YR_123_000002_runtime.log",
"YR_123_000002_runtime.1.log",
"YR_123_000002_runtime.log.gz",
"YR_123_000002_runtime.log.gz.10086",
"YR_123_000003_runtime.log",
"YR_123_000003_runtime.1755842461755699.log.gz",
"YR_123_000003_runtime.1755971816292456.log.gz.1123",
"YR_123_000003_libruntime.log",
"YR_123_000003_libruntime.1755842461755699.log.gz",
};
for (auto logName : logNameList) {
std::string logFileName = litebus::os::Join(LOG_BASE_DIR, logName);
int fd = open(logFileName.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(logFileName);
outfile << "runtime log #" << logFileName << ". This is a Test." << std::endl;
outfile.close();
YRLOG_DEBUG("Creating log files for: {}", logFileName);
}
}
void MockCreateManyPrefixLogs(int cnt = 100)
{
(void)litebus::os::Mkdir(LOG_BASE_DIR);
for (int i = 0; i < cnt; i++) {
std::string logFileName = litebus::os::Join(LOG_BASE_DIR, "YR_123_000005_xxx." + std::to_string(i) + ".log");
int fd = open(logFileName.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
EXPECT_NE(fd, -1);
close(fd);
std::ofstream outfile;
outfile.open(logFileName);
outfile << "runtime log #" << logFileName << ". This is a Test." << std::endl;
outfile.close();
YRLOG_DEBUG("Creating log files for: {}", logFileName);
}
}
void SetUp() override
{
(void)litebus::os::Rmdir(LOG_BASE_DIR);
testActor_ = std::make_shared<RuntimeManagerTestActor>(GenerateRandomName("randomRuntimeManagerTestActor"));
litebus::Spawn(testActor_, true);
helper_ =
std::make_shared<LogManagerActorHelper>(GenerateRandomName("LogManagerActorHelper"), testActor_->GetAID());
litebus::Spawn(helper_);
}
void TearDown() override
{
litebus::Terminate(helper_->GetAID());
litebus::Await(helper_->GetAID());
litebus::Terminate(testActor_->GetAID());
litebus::Await(testActor_->GetAID());
helper_ = nullptr;
testActor_ = nullptr;
}
protected:
std::shared_ptr<LogManagerActorHelper> helper_;
std::shared_ptr<RuntimeManagerTestActor> testActor_;
std::string pythonRuntimeID_;
std::string javaRuntimeID_;
std::string cppRuntimeID_;
std::string libRuntimeID_;
std::string pythonRollingRuntimeID_;
std::string cppRollingRuntimeID_;
std::string cppRollingCompressionRuntimeID_;
};
TEST_F(LogManagerTest, EmptyLogDir)
{
(void)litebus::os::Mkdir(LOG_BASE_DIR);
const char *argv[] = { "./runtime-manager", "--runtime_logs_dir=/tmp/snuser/log", "--log_expiration_enable=true",
"--log_expiration_cleanup_interval=0", "--log_expiration_max_file_count=100" };
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(0);
});
}
TEST_F(LogManagerTest, LogFileExpirationNotExpired1)
{
MockCreateLogs();
const char *argv[] = { "./runtime-manager", "--runtime_logs_dir=/tmp/snuser/log", "--log_expiration_enable=true",
"--log_expiration_cleanup_interval=0", "--log_expiration_max_file_count=100" };
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(5);
});
}
TEST_F(LogManagerTest, LogFileExpirationNotExpired2)
{
MockCreateLogs();
EXPECT_CALL(*helper_, IsRuntimeActive(_))
.WillRepeatedly([javaRuntimeID(javaRuntimeID_)](const std::string &runtimeID) {
if (runtimeID == javaRuntimeID) {
return litebus::Future<bool>(false);
}
return litebus::Future<bool>(true);
});
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=3",
"--log_expiration_max_file_count=0",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(5);
});
}
TEST_F(LogManagerTest, LogFileExpirationNotExpired3)
{
MockCreateLogs();
EXPECT_CALL(*helper_, IsRuntimeActive(_))
.WillRepeatedly([javaRuntimeID(javaRuntimeID_)](const std::string &runtimeID) {
if (runtimeID == javaRuntimeID) {
return litebus::Future<bool>(false);
}
return litebus::Future<bool>(true);
});
const char *argv[] = { "./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=1",
"--log_expiration_max_file_count=10",
"--runtime_std_log_dir=instances"};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(5);
});
}
TEST_F(LogManagerTest, LogFileExpirationExpired1)
{
MockCreateLogs();
EXPECT_CALL(*helper_, IsRuntimeActive(_))
.WillRepeatedly([javaRuntimeID(javaRuntimeID_)](const std::string &runtimeID) {
if (runtimeID == javaRuntimeID) {
return litebus::Future<bool>(false);
}
return litebus::Future<bool>(true);
});
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=1",
"--log_expiration_max_file_count=0",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(4);
});
}
TEST_F(LogManagerTest, LogFileExpirationExpired2)
{
MockCreateLogs();
EXPECT_CALL(*helper_, IsRuntimeActive(_)).WillRepeatedly(Return(false));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=1",
"--log_expiration_max_file_count=2",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(4)
|| files.Get().size()
== static_cast<size_t>(3);
});
}
TEST_F(LogManagerTest, LogFileExpirationExpired3)
{
MockCreateLibRuntimeLogs();
MockCreateCppRuntimeLogs2();
EXPECT_CALL(*helper_, IsRuntimeActive(_)).WillRepeatedly(Return(false));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=0",
"--log_expiration_max_file_count=0"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(0);
});
}
TEST_F(LogManagerTest, LogFileExpirationExpiredAsync)
{
MockCreateLogs();
litebus::Promise<bool> javaPromise;
litebus::Promise<bool> cppPromise;
EXPECT_CALL(*helper_, IsRuntimeActive(_))
.WillRepeatedly([javaRuntimeID(javaRuntimeID_), cppRuntimeID(cppRuntimeID_), &javaPromise,
&cppPromise](const std::string &runtimeID) {
if (runtimeID == javaRuntimeID) {
std::cout << "Checking Java runtime status..." << std::endl;
return javaPromise.GetFuture();
} else if (runtimeID == cppRuntimeID) {
std::cout << "Checking C++ runtime status..." << std::endl;
return cppPromise.GetFuture();
}
return litebus::Future<bool>(true);
});
std::thread javaThread([&javaPromise]() {
std::this_thread::sleep_for(std::chrono::milliseconds(400));
javaPromise.SetValue(false);
});
std::thread cppThread([&cppPromise]() {
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
cppPromise.SetValue(false);
});
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=1",
"--log_expiration_time_threshold=0",
"--log_expiration_max_file_count=0",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
helper_->ScanLogsRegularly();
javaThread.join();
cppThread.join();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(3);
});
}
* Test Steps:
* 1. Simulate runtime log generation: Create multiple logs, named according to runtime logs and compressed files
* 2. Set log aging deletion configuration
* 3. In the waiting time, without expiration
* 4. Call the CleanLogs function to check if the unexpired file has been deleted
*/
TEST_F(LogManagerTest, LogFileExpirationComplexCaseWithRollingCompressionTest)
{
MockCreateLogs();
MockCreateCppRuntimeRollingLogs();
MockCreatePythonRuntimeRollingLogs();
MockCreateCppRuntimeRollingLogsWithCompression();
EXPECT_CALL(*helper_, IsRuntimeActive(_)).WillRepeatedly(Return(false));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=1",
"--log_expiration_time_threshold=1",
"--log_expiration_max_file_count=1",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(3);
});
auto files = litebus::os::Ls(LOG_BASE_DIR);
}
TEST_F(LogManagerTest, DsClientLogFileExpirationNotExpired)
{
MockCreateDsClientLogs();
EXPECT_CALL(*helper_, IsRuntimeActiveByPid(_)).WillRepeatedly(Return(true));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=1",
"--log_expiration_max_file_count=0",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(9);
});
}
TEST_F(LogManagerTest, DsClientLogFileExpirationExpired)
{
MockCreateDsClientLogs();
EXPECT_CALL(*helper_, IsRuntimeActiveByPid(_)).WillRepeatedly(Return(false));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=1",
"--log_expiration_max_file_count=0",
"--runtime_std_log_dir=instances"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(0);
});
}
TEST_F(LogManagerTest, AcquireLogPrefix)
{
auto pid = std::to_string(getpid());
helper_->logCount_ = 999998;
auto res1 = helper_->AcquireLogPrefix("runtime1");
auto exp1 = "YR_" + pid + "_000000";
EXPECT_EQ(res1.Get(), exp1);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp1], "runtime1");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime1"], exp1);
auto res2 = helper_->AcquireLogPrefix("runtime2");
auto res3 = helper_->AcquireLogPrefix("runtime3");
auto exp2 = "YR_" + pid + "_000001";
auto exp3 = "YR_" + pid + "_000002";
auto exp4 = "YR_" + pid + "_000003";
EXPECT_EQ(res2.Get(), exp2);
EXPECT_EQ(res3.Get(), exp3);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp2], "runtime2");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime2"], exp2);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp3], "runtime3");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime3"], exp3);
helper_->ReleaseLogPrefix("runtime2");
helper_->ReleaseLogPrefix("runtime3");
res1 = helper_->AcquireLogPrefix("runtime4");
res2 = helper_->AcquireLogPrefix("runtime5");
EXPECT_EQ(res1.Get(), exp3);
EXPECT_EQ(res2.Get(), exp2);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp3], "runtime4");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime4"], exp3);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp2], "runtime5");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime5"], exp2);
res2 = helper_->AcquireLogPrefix("runtime6");
EXPECT_EQ(res2.Get(), exp4);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp4], "runtime6");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime6"], exp4);
}
TEST_F(LogManagerTest, ReleaseLogPrefix)
{
auto pid = std::to_string(getpid());
auto res1 = helper_->AcquireLogPrefix("runtime1");
auto exp1 = "YR_" + pid + "_000001";
EXPECT_EQ(res1.Get(), exp1);
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp1], "runtime1");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime1"], exp1);
helper_->ReleaseLogPrefix("runtime2");
EXPECT_EQ(helper_->logPrefix2RuntimeID_[exp1], "runtime1");
EXPECT_EQ(helper_->runtimeID2LogPrefix_["runtime1"], exp1);
helper_->ReleaseLogPrefix("runtime1");
EXPECT_EQ(helper_->logPrefix2RuntimeID_.find(exp1), helper_->logPrefix2RuntimeID_.end());
EXPECT_EQ(helper_->runtimeID2LogPrefix_.find("runtime1"), helper_->runtimeID2LogPrefix_.end());
EXPECT_EQ(helper_->logPrefixDequeue_.front(), exp1);
helper_->runtimeID2LogPrefix_["runtime2"] = "log1111";
helper_->logPrefix2RuntimeID_["log2222"] = "runtime2";
helper_->runtimeID2LogPrefix_["runtime3"] = "log2222";
helper_->ReleaseLogPrefix("runtime2");
EXPECT_TRUE(helper_->logPrefix2RuntimeID_.find("log2222") != helper_->logPrefix2RuntimeID_.end());
helper_->ReleaseLogPrefix("runtime3");
EXPECT_TRUE(helper_->logPrefix2RuntimeID_.find("log2222") != helper_->logPrefix2RuntimeID_.end());
}
TEST_F(LogManagerTest, AddLogAndPopLogTest)
{
size_t toDeleteCount = 200;
for (size_t i = 0; i < toDeleteCount; i++) {
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/tmp/xxx_"+std::to_string(i), 1756216109, false),
false);
}
std::vector<std::shared_ptr<RuntimeLogFile>> toBeDeleteFiles;
for (size_t i = 0; i < toDeleteCount; ++i) {
auto file = helper_->expiredLogQueue_->PopLogFile();
if (file == nullptr){
break;
}
toBeDeleteFiles.emplace_back(file);
}
EXPECT_TRUE(toBeDeleteFiles.size() == toDeleteCount);
}
TEST_F(LogManagerTest, AddAndPopLogTest)
{
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/tmp/xxx_0", 1756216109, false),
true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/java/file_"+std::to_string(0), 1756216110, false),
true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/java/file_"+std::to_string(1), 1756216110, false),
true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/java/file_"+std::to_string(2), 1756216110, false),
true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/javaDir/", 1756216110, true),
true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/tmp/xxx_100", 1756216111, false),
true);
std::vector<bool> expectDir = {false, false, false, false, true, false};
std::vector<std::string> expectStr = {"/tmp/xxx_0", "/java/file_", "/java/file_", "/java/file_", "/javaDir/", "/tmp/xxx_100",};
for (size_t i = 0; i < 6; ++i) {
auto file = helper_->expiredLogQueue_->PopLogFile();
EXPECT_TRUE(file->GetFilePath().substr(0, expectStr[i].size()) == expectStr[i]);
EXPECT_EQ(file->IsDir(), expectDir[i]);
}
ASSERT_TRUE(helper_->expiredLogQueue_->PopLogFile() == nullptr);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/tmp/xxx_1", 1756216109, false), true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/tmp/xxx_2", 1756216109, false), true);
helper_->expiredLogQueue_->AddLogFile(std::make_shared<RuntimeLogFile>("", "/tmp/xxx_3", 1756216109, false), true);
helper_->expiredLogQueue_->Reset();
ASSERT_TRUE(helper_->expiredLogQueue_->PopLogFile() == nullptr);
}
TEST_F(LogManagerTest, RecycleReuseLogTest)
{
MockCreatePrefixLogs();
MockCreateDsClientLogs();
MockCreateManyPrefixLogs(200);
helper_->logReuse_ = true;
EXPECT_CALL(*helper_, IsRuntimeActive(_)).WillRepeatedly(Return(false));
EXPECT_CALL(*helper_, IsRuntimeActiveByPid(_)).WillRepeatedly(Return(false));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=10",
"--log_expiration_time_threshold=0",
"--log_expiration_max_file_count=0"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(0);
});
auto files = litebus::os::Ls(LOG_BASE_DIR);
}
TEST_F(LogManagerTest, RecycleReuseLogWhileReusingTest)
{
MockCreatePrefixLogs();
MockCreateDsClientLogs();
MockCreateManyPrefixLogs(200);
helper_->logReuse_ = true;
helper_->logPrefix2RuntimeID_["YR_123_000003"] = "runtime3";
helper_->logPrefix2RuntimeID_["YR_123_000002"] = "runtime2";
EXPECT_CALL(*helper_, IsRuntimeActive(_))
.WillRepeatedly([](const std::string &runtimeID) {
if (runtimeID == "runtime3") {
return litebus::Future<bool>(true);
}
return litebus::Future<bool>(false);
});
EXPECT_CALL(*helper_, IsRuntimeActiveByPid(_)).WillOnce(Return(true)).WillRepeatedly(Return(false));
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=30",
"--log_expiration_time_threshold=0",
"--log_expiration_max_file_count=3"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
helper_->ScanLogsRegularly();
EXPECT_AWAIT_TRUE_FOR([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(6);
}, 5000);
auto files = litebus::os::Ls(LOG_BASE_DIR);
}
TEST_F(LogManagerTest, RecycleReuseLogWhileReusingAsyncTest)
{
MockCreatePrefixLogs();
MockCreateDsClientLogs();
MockCreateManyPrefixLogs(200);
helper_->logReuse_ = true;
helper_->logPrefix2RuntimeID_["YR_123_000003"] = "runtime3";
helper_->logPrefix2RuntimeID_["YR_123_000002"] = "runtime2";
litebus::Promise<bool> promise1;
litebus::Promise<bool> promise2;
EXPECT_CALL(*helper_, IsRuntimeActive(_))
.WillRepeatedly([javaRuntimeID(javaRuntimeID_), cppRuntimeID(cppRuntimeID_), &promise1,
&promise2](const std::string &runtimeID) {
if (runtimeID == "runtime3") {
return promise1.GetFuture();
} else if (runtimeID == "runtime2") {
return promise2.GetFuture();
}
return litebus::Future<bool>(true);
});
EXPECT_CALL(*helper_, IsRuntimeActiveByPid(_)).WillOnce(Return(true)).WillRepeatedly(Return(false));
std::thread runtimeThread1([&promise1]() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
promise1.SetValue(true);
});
std::thread runtimeThread2([&promise2]() {
std::this_thread::sleep_for(std::chrono::milliseconds(300));
promise2.SetValue(false);
});
const char *argv[] = {
"./runtime-manager",
"--runtime_logs_dir=/tmp/snuser/log",
"--log_expiration_enable=true",
"--log_expiration_cleanup_interval=30",
"--log_expiration_time_threshold=0",
"--log_expiration_max_file_count=3"
};
runtime_manager::Flags flags;
flags.ParseFlags(std::size(argv), argv);
helper_->SetConfig(flags);
helper_->ScanLogsRegularly();
runtimeThread1.join();
runtimeThread2.join();
EXPECT_AWAIT_TRUE_FOR([=]() -> bool {
auto files = litebus::os::Ls(LOG_BASE_DIR);
return files.Get().size() == static_cast<size_t>(6);
}, 5000);
auto files = litebus::os::Ls(LOG_BASE_DIR);
}
}