* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio 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 <gtest/gtest.h>
#include <gmock/gmock.h>
#include "msServiceProfiler/SecurityUtils.h"
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <dlfcn.h>
#include "msServiceProfiler/SecurityUtilsLog.h"
using namespace SecurityUtils;
using namespace testing;
static int (*real_stat)(const char*, struct stat*) = nullptr;
struct MockControl {
bool real_func = true;
bool bool_return = false;
int int_return = 0;
int call_count = 0;
};
static MockControl mock_control;
extern "C" int stat(const char* path, struct stat* buf)
{
mock_control.call_count++;
if (mock_control.real_func) {
real_stat = reinterpret_cast<decltype(real_stat)>(
dlsym(RTLD_NEXT, "stat")
);
return real_stat(path, buf);
}
return mock_control.int_return;
}
class SecurityUtilsTest : public Test {
protected:
void SetUp() override
{
const char* tempFile = "testfile.txt";
const char* tempDir = "testdir";
const char* tempLink = "testlink";
FILE* file = fopen(tempFile, "w");
if (file) {
fclose(file);
}
mkdir(tempDir, 0755);
symlink(tempFile, tempLink);
mock_control = MockControl{};
}
void TearDown() override
{
const char* tempFile = "testfile.txt";
const char* tempDir = "testdir";
const char* tempLink = "testlink";
unlink(tempFile);
rmdir(tempDir);
unlink(tempLink);
mock_control.real_func = true;
mock_control.bool_return = false;
mock_control.int_return = 0;
mock_control.call_count = 0;
}
};
TEST_F(SecurityUtilsTest, TestIsExist)
{
const std::string existingFile = "testfile.txt";
EXPECT_TRUE(IsExist(existingFile));
const std::string nonExistingFile = "nonexistent.txt";
EXPECT_FALSE(IsExist(nonExistingFile));
}
TEST_F(SecurityUtilsTest, TestIsReadable)
{
const std::string readableFile = "testfile.txt";
EXPECT_TRUE(IsReadable(readableFile));
const std::string unreadableFile = "testfile.txt";
chmod(unreadableFile.c_str(), 0000);
EXPECT_FALSE(IsReadable(unreadableFile));
chmod(unreadableFile.c_str(), 0644);
}
TEST_F(SecurityUtilsTest, TestIsReadable_001)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string readableFile = "testfile.txt";
}
TEST_F(SecurityUtilsTest, TestIsWritable)
{
const std::string writableFile = "testfile.txt";
EXPECT_TRUE(IsWritable(writableFile));
const std::string unwritableFile = "testfile.txt";
chmod(unwritableFile.c_str(), 0444);
EXPECT_FALSE(IsWritable(unwritableFile));
chmod(unwritableFile.c_str(), 0644);
}
TEST_F(SecurityUtilsTest, TestIsWritable_002)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string writableFile = "testfile.txt";
}
TEST_F(SecurityUtilsTest, TestIsExecutable)
{
const std::string nonExecutableFile = "testfile.txt";
EXPECT_FALSE(IsExecutable(nonExecutableFile));
const std::string executableFile = "test.sh";
FILE* file = fopen(executableFile.c_str(), "w");
if (file) {
fclose(file);
chmod(executableFile.c_str(), 0755);
EXPECT_TRUE(IsExecutable(executableFile));
unlink(executableFile.c_str());
}
}
TEST_F(SecurityUtilsTest, TestIsExecutable_002)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string nonExecutableFile = "testfile.txt";
EXPECT_FALSE(IsExecutable(nonExecutableFile));
}
TEST_F(SecurityUtilsTest, TestIsOwner_001)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string normalFile = "testfile.txt";
}
TEST_F(SecurityUtilsTest, TestIsSoftLink)
{
const std::string softLink = "testlink";
EXPECT_TRUE(IsSoftLink(softLink));
const std::string nonSoftLink = "testfile.txt";
EXPECT_FALSE(IsSoftLink(nonSoftLink));
}
TEST_F(SecurityUtilsTest, TestIsSoftLink_001)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string softLink = "testlink";
EXPECT_TRUE(IsSoftLink(softLink));
}
TEST_F(SecurityUtilsTest, TestIsFile)
{
const std::string regularFile = "testfile.txt";
EXPECT_TRUE(IsFile(regularFile));
const std::string directory = "testdir";
EXPECT_FALSE(IsFile(directory));
}
TEST_F(SecurityUtilsTest, TestIsFile_001)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string regularFile = "testfile.txt";
}
TEST_F(SecurityUtilsTest, TestIsDir)
{
const std::string directory = "testdir";
EXPECT_TRUE(IsDir(directory));
const std::string regularFile = "testfile.txt";
EXPECT_FALSE(IsDir(regularFile));
}
TEST_F(SecurityUtilsTest, TestIsDir_001)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string directory = "testdir";
}
TEST_F(SecurityUtilsTest, TestIsPathLenLegal)
{
const std::string shortPath = "testfile.txt";
EXPECT_TRUE(IsPathLenLegal(shortPath));
std::string longPath(PATH_MAX, 'a');
EXPECT_FALSE(IsPathLenLegal(longPath));
}
TEST_F(SecurityUtilsTest, TestIsPathDepthLegal)
{
const std::string shallowPath = "testdir/testfile.txt";
EXPECT_TRUE(IsPathDepthLegal(shallowPath));
std::string deepPath;
for (int i = 0; i < PATH_DEPTH_MAX + 1; ++i) {
deepPath += "/testdir";
}
EXPECT_FALSE(IsPathDepthLegal(deepPath));
}
TEST_F(SecurityUtilsTest, TestIsPathLenLegal_001)
{
const std::string shortPath = "";
EXPECT_FALSE(IsPathLenLegal(shortPath));
}
TEST_F(SecurityUtilsTest, TestIsFileSizeLegal)
{
const std::string smallFile = "testfile.txt";
const long long maxSize = 1024;
EXPECT_TRUE(IsFileSizeLegal(smallFile, maxSize));
const std::string largeFile = "testfile.txt";
FILE* file = fopen(largeFile.c_str(), "w");
if (file) {
const char* data = "0123456789";
for (int i = 0; i < 1000; ++i) {
fwrite(data, sizeof(char), strlen(data), file);
}
fclose(file);
EXPECT_FALSE(IsFileSizeLegal(largeFile, maxSize));
unlink(largeFile.c_str());
}
}
TEST_F(SecurityUtilsTest, TestIsFileSizeLegal_001)
{
mock_control.real_func = false;
mock_control.int_return = 1;
const std::string smallFile = "testfile.txt";
const long long maxSize = 1024;
}
TEST_F(SecurityUtilsTest, TestIsPathCharactersValid)
{
const std::string validPath = "testfile.txt";
EXPECT_TRUE(IsPathCharactersValid(validPath));
const std::string invalidPath = "test?file.txt";
EXPECT_FALSE(IsPathCharactersValid(invalidPath));
}
TEST_F(SecurityUtilsTest, TestIsPathCharactersValid_001)
{
const std::string validPath = "testfile";
EXPECT_TRUE(IsPathCharactersValid(validPath));
}
TEST_F(SecurityUtilsTest, TestCheckPathContainSoftLink)
{
const std::string pathWithLink = "testlink";
EXPECT_TRUE(CheckPathContainSoftLink(pathWithLink));
const std::string pathWithoutLink = "testfile.txt";
EXPECT_FALSE(CheckPathContainSoftLink(pathWithoutLink));
}
TEST_F(SecurityUtilsTest, TestCheckFileBeforeWrite)
{
const std::string validFile = "testfile.txt";
CheckFileBeforeWrite(validFile);
const std::string link = "testlink";
EXPECT_FALSE(CheckFileBeforeWrite(link));
}
TEST_F(SecurityUtilsTest, TestCheckFileBeforeWrite_001)
{
const std::string fileName = "";
EXPECT_FALSE(CheckFileBeforeWrite(fileName));
fileName = "test;file";
EXPECT_FALSE(CheckFileBeforeWrite(fileName));
}
TEST_F(SecurityUtilsTest, TestCheckFileBeforeRead)
{
const std::string validFile = "testfile.txt";
const long long maxSize = 1024;
CheckFileBeforeRead(validFile, maxSize);
const std::string link = "testlink";
EXPECT_FALSE(CheckFileBeforeRead(link, maxSize));
}
TEST_F(SecurityUtilsTest, TestSetLogLevelByEnvVar)
{
SecurityUtilsLog::GetLog().SetLogLevelByEnvVar();
setenv("SECURITY_UTILS_LOG_LEVEL", "1", 1);
SecurityUtilsLog::GetLog().SetLogLevelByEnvVar();
setenv("SECURITY_UTILS_LOG_LEVEL", "9", 1);
SecurityUtilsLog::GetLog().SetLogLevelByEnvVar();
ToSafeString("\n");
const auto& map = GetInvalidChar();
EXPECT_EQ(map.at("\n"), "\\n");
EXPECT_EQ(map.at("\f"), "\\f");
EXPECT_EQ(map.at("\r"), "\\r");
EXPECT_EQ(map.at("\b"), "\\b");
EXPECT_EQ(map.at("\t"), "\\t");
EXPECT_EQ(map.at("\v"), "\\v");
EXPECT_EQ(map.at("\u007F"), "\\u007F");
EXPECT_THROW(map.at("not_exist"), std::out_of_range);
}
static struct tm* (*real_localtime)(const time_t*, struct tm*) = nullptr;
struct TimeMockControl {
bool real_func = true;
struct tm mock_return;
};
static TimeMockControl time_mock_control;
TEST_F(SecurityUtilsTest, TestAddPrefixInfo)
{
time_mock_control.real_func = false;
std::string lengthLimit = "Log length reach limit,only show part message";
SecurityUtilsLog::GetLog().AddPrefixInfo(lengthLimit, LogLv::INFO);
}