* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it
* under the terms of CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* 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 FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* \file test_sk_file_logger.cpp
* \brief 文件日志器单元测试
*/
#include <gtest/gtest.h>
#include <fstream>
#include <thread>
#include "sk_file_logger.h"
using namespace sk::logger;
class SkFileLoggerTest : public ::testing::Test {
protected:
void SetUp() override {
testLogDir_ = "test_logs";
}
void TearDown() override {
system(("rm -rf " + testLogDir_).c_str());
}
std::string testLogDir_;
};
TEST_F(SkFileLoggerTest, BasicInitialization) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_1";
config.baseDir = testLogDir_;
config.minLevel = LogLevel::DEBUG;
EXPECT_TRUE(FileLogger::Instance().Initialize(config));
EXPECT_TRUE(FileLogger::Instance().IsInitialized());
EXPECT_TRUE(FileLogger::Instance().IsEnabled());
}
TEST_F(SkFileLoggerTest, DisabledInitialization) {
LoggerConfig config;
config.enabled = false;
config.modelLabel = "test_model_2";
config.baseDir = testLogDir_;
EXPECT_TRUE(FileLogger::Instance().Initialize(config));
EXPECT_TRUE(FileLogger::Instance().IsInitialized());
EXPECT_FALSE(FileLogger::Instance().IsEnabled());
}
TEST_F(SkFileLoggerTest, LogWithOriginalMacros) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_3";
config.baseDir = testLogDir_;
config.minLevel = LogLevel::DEBUG;
FileLogger::Instance().Initialize(config);
SK_LOGI("Test info message");
SK_LOGD("Test debug message: %d", 42);
SK_LOGW("Test warning message");
SK_LOGE("Test error message");
EXPECT_TRUE(FileLogger::Instance().IsEnabled());
}
TEST_F(SkFileLoggerTest, RAIIContext) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_4";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
{
SK_LOG_CONTEXT_SIMPLE("context_test.log");
SK_LOGI("This should go to context_test.log");
EXPECT_EQ(FileHandleManager::Instance().GetCurrentHandle(), "context_test.log");
}
EXPECT_EQ(FileHandleManager::Instance().GetCurrentHandle(), "default");
}
TEST_F(SkFileLoggerTest, LogLevelFiltering) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_5";
config.baseDir = testLogDir_;
config.minLevel = LogLevel::WARNING;
FileLogger::Instance().Initialize(config);
SK_LOGD("Debug message - should be filtered");
SK_LOGI("Info message - should be filtered");
SK_LOGW("Warning message - should be logged");
SK_LOGE("Error message - should be logged");
FileLogger::Instance().SetMinLevel(LogLevel::INFO);
SK_LOGI("Info message - should now be logged");
}
TEST_F(SkFileLoggerTest, DynamicToggle) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_6";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
EXPECT_TRUE(FileLogger::Instance().IsEnabled());
SK_LOGI("Enabled: this should be logged");
FileLogger::Instance().SetEnabled(false);
EXPECT_FALSE(FileLogger::Instance().IsEnabled());
SK_LOGI("Disabled: this should not be logged to file");
FileLogger::Instance().SetEnabled(true);
EXPECT_TRUE(FileLogger::Instance().IsEnabled());
SK_LOGI("Re-enabled: this should be logged again");
}
TEST_F(SkFileLoggerTest, ThreadSafety) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_7";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
const int numThreads = 10;
const int logsPerThread = 100;
std::vector<std::thread> threads;
for (int t = 0; t < numThreads; ++t) {
threads.emplace_back([t, logsPerThread]() {
for (int i = 0; i < logsPerThread; ++i) {
SK_LOGI("Thread %d, log %d", t, i);
}
});
}
for (auto& thread : threads) {
thread.join();
}
SUCCEED();
}
TEST_F(SkFileLoggerTest, FileHandleManagement) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_8";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
EXPECT_TRUE(FileLogger::Instance().RegisterLogFile("module1.log"));
EXPECT_TRUE(FileLogger::Instance().RegisterLogFile("module2.log"));
EXPECT_TRUE(FileLogger::Instance().SwitchToFile("module1.log"));
SK_LOGI("Log to module1");
EXPECT_TRUE(FileLogger::Instance().SwitchToFile("module2.log"));
SK_LOGI("Log to module2");
FileLogger::Instance().SwitchToDefault();
SK_LOGI("Log to default");
}
TEST_F(SkFileLoggerTest, LongLogSegmentation) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "test_model_9";
config.baseDir = testLogDir_;
config.maxLineLength = 100;
FileLogger::Instance().Initialize(config);
std::string longMessage(500, 'X');
SK_LOGI("Long message: %s", longMessage.c_str());
SUCCEED();
}
TEST_F(SkFileLoggerTest, ModelRIDirectory) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "model_with_special_chars/test";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
SK_LOGI("Test with modelRI containing special characters");
SUCCEED();
}
TEST_F(SkFileLoggerTest, SimplifiedMacros) {
InitializeSkFileLogger(true, "test_model_11", LogLevel::DEBUG);
SK_LOGI("Using simplified initialization macro");
DISABLE_SK_FILE_LOGGER();
SK_LOGI("This should not be logged to file");
EXPECT_TRUE(true);
}
TEST_F(SkFileLoggerTest, DISABLED_PerformanceBenchmark) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "perf_test";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
const int logCount = 10000;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < logCount; ++i) {
SK_LOGI("Performance test log %d", i);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Logged " << logCount << " messages in "
<< duration.count() << " ms" << std::endl;
std::cout << "Average: " << (duration.count() * 1000.0 / logCount)
<< " microseconds per log" << std::endl;
}
TEST_F(SkFileLoggerTest, NestedRAIIContext) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "nested_test";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
SK_LOGI("Default context");
{
SK_LOG_CONTEXT_SIMPLE("outer.log");
SK_LOGI("Outer context");
{
SK_LOG_CONTEXT_SIMPLE("inner.log");
SK_LOGI("Inner context");
EXPECT_EQ(FileHandleManager::Instance().GetCurrentHandle(), "inner.log");
}
}
EXPECT_EQ(FileHandleManager::Instance().GetCurrentHandle(), "default");
}
TEST_F(SkFileLoggerTest, EmptyMessage) {
LoggerConfig config;
config.enabled = true;
config.modelLabel = "empty_test";
config.baseDir = testLogDir_;
FileLogger::Instance().Initialize(config);
SK_LOGI("");
SK_LOGI(nullptr);
SUCCEED();
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}