2026-01-22 15:51:03 -05:00
|
|
|
#include <gtest/gtest.h>
|
2026-04-07 14:05:04 -04:00
|
|
|
#include "process_stats.h"
|
2026-03-27 12:33:38 -04:00
|
|
|
#include <nlohmann/json.hpp>
|
2026-04-07 14:05:04 -04:00
|
|
|
#include <chrono>
|
|
|
|
|
#include <csignal>
|
2026-01-22 15:51:03 -05:00
|
|
|
#include <cstring>
|
2026-04-07 14:05:04 -04:00
|
|
|
#include <thread>
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
#include <vector>
|
2026-01-22 15:51:03 -05:00
|
|
|
#include <unistd.h>
|
2026-04-07 14:05:04 -04:00
|
|
|
#include <sys/wait.h>
|
2026-01-22 15:51:03 -05:00
|
|
|
|
|
|
|
|
class ProcessStatsTest : public ::testing::Test {
|
|
|
|
|
protected:
|
2026-04-07 14:05:04 -04:00
|
|
|
std::vector<pid_t> m_childPids;
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
void SetUp() override
|
|
|
|
|
{
|
2026-03-24 16:50:23 -04:00
|
|
|
ProcessStats::clearHistory();
|
2026-01-22 15:51:03 -05:00
|
|
|
}
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
void TearDown() override
|
|
|
|
|
{
|
2026-03-24 16:50:23 -04:00
|
|
|
ProcessStats::clearHistory();
|
2026-04-07 14:05:04 -04:00
|
|
|
for (pid_t pid : m_childPids) {
|
|
|
|
|
if (pid > 0) {
|
|
|
|
|
kill(pid, SIGTERM);
|
|
|
|
|
int st = 0;
|
|
|
|
|
waitpid(pid, &st, 0);
|
2026-01-22 15:51:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-07 14:05:04 -04:00
|
|
|
m_childPids.clear();
|
2026-01-22 15:51:03 -05:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_ReturnsZeroedStatsForNegativePid)
|
|
|
|
|
{
|
2026-03-24 16:50:23 -04:00
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(-1);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_EQ(stats.cpuPercent, 0.0);
|
|
|
|
|
EXPECT_EQ(stats.cpuTimeSeconds, 0.0);
|
|
|
|
|
EXPECT_EQ(stats.memoryMB, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_ReturnsZeroedStatsForZeroPid)
|
|
|
|
|
{
|
2026-03-24 16:50:23 -04:00
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(0);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_EQ(stats.cpuPercent, 0.0);
|
|
|
|
|
EXPECT_EQ(stats.cpuTimeSeconds, 0.0);
|
|
|
|
|
EXPECT_EQ(stats.memoryMB, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_ReturnsValidStatsForCurrentProcess)
|
|
|
|
|
{
|
|
|
|
|
int64_t currentPid = static_cast<int64_t>(getpid());
|
2026-03-24 16:50:23 -04:00
|
|
|
|
|
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(currentPid);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_GT(stats.memoryMB, 0.0);
|
|
|
|
|
EXPECT_GE(stats.cpuTimeSeconds, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_MemoryIsNonNegative)
|
|
|
|
|
{
|
|
|
|
|
int64_t currentPid = static_cast<int64_t>(getpid());
|
2026-03-24 16:50:23 -04:00
|
|
|
|
|
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(currentPid);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_GE(stats.memoryMB, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_CpuTimeIsNonNegative)
|
|
|
|
|
{
|
|
|
|
|
int64_t currentPid = static_cast<int64_t>(getpid());
|
2026-03-24 16:50:23 -04:00
|
|
|
|
|
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(currentPid);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_GE(stats.cpuTimeSeconds, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_CpuPercentIsZeroOnFirstCall)
|
|
|
|
|
{
|
|
|
|
|
int64_t currentPid = static_cast<int64_t>(getpid());
|
2026-03-24 16:50:23 -04:00
|
|
|
|
|
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(currentPid);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_EQ(stats.cpuPercent, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetProcessStats_CpuPercentUpdatesOnSecondCall)
|
|
|
|
|
{
|
|
|
|
|
int64_t currentPid = static_cast<int64_t>(getpid());
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
ProcessStats::getProcessStats(currentPid);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
volatile double sum = 0.0;
|
|
|
|
|
for (int i = 0; i < 1000000; ++i) {
|
|
|
|
|
sum += i * 0.1;
|
|
|
|
|
}
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
usleep(10000);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
|
|
|
|
ProcessStats::ProcessStatsData stats = ProcessStats::getProcessStats(currentPid);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_GE(stats.cpuPercent, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetModuleStats_ReturnsEmptyArrayWhenNoPlugins)
|
|
|
|
|
{
|
|
|
|
|
std::unordered_map<std::string, int64_t> processes;
|
2026-03-24 16:50:23 -04:00
|
|
|
char* result = ProcessStats::getModuleStats(processes);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
ASSERT_NE(result, nullptr);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-03-27 12:33:38 -04:00
|
|
|
nlohmann::json doc = nlohmann::json::parse(result);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-03-27 12:33:38 -04:00
|
|
|
EXPECT_TRUE(doc.is_array());
|
2026-04-07 14:05:04 -04:00
|
|
|
EXPECT_EQ(doc.size(), 0u);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
delete[] result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetModuleStats_ReturnsNonNullPointer)
|
|
|
|
|
{
|
|
|
|
|
std::unordered_map<std::string, int64_t> processes;
|
2026-03-24 16:50:23 -04:00
|
|
|
char* result = ProcessStats::getModuleStats(processes);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
ASSERT_NE(result, nullptr);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
delete[] result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
TEST_F(ProcessStatsTest, GetModuleStats_ReturnsValidJsonStructure)
|
|
|
|
|
{
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
|
ASSERT_GE(pid, 0);
|
|
|
|
|
if (pid == 0) {
|
|
|
|
|
execlp("sleep", "sleep", "2", nullptr);
|
|
|
|
|
_exit(127);
|
|
|
|
|
}
|
|
|
|
|
m_childPids.push_back(pid);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-04-07 14:05:04 -04:00
|
|
|
std::unordered_map<std::string, int64_t> processes;
|
|
|
|
|
processes["test_plugin"] = static_cast<int64_t>(pid);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
|
|
|
|
char* result = ProcessStats::getModuleStats(processes);
|
|
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
ASSERT_NE(result, nullptr);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-03-27 12:33:38 -04:00
|
|
|
nlohmann::json doc = nlohmann::json::parse(result);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-03-27 12:33:38 -04:00
|
|
|
EXPECT_TRUE(doc.is_array());
|
2026-04-07 14:05:04 -04:00
|
|
|
ASSERT_EQ(doc.size(), 1u);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-03-27 12:33:38 -04:00
|
|
|
auto moduleObj = doc[0];
|
2026-01-22 15:51:03 -05:00
|
|
|
EXPECT_TRUE(moduleObj.contains("name"));
|
|
|
|
|
EXPECT_TRUE(moduleObj.contains("cpu_percent"));
|
|
|
|
|
EXPECT_TRUE(moduleObj.contains("cpu_time_seconds"));
|
|
|
|
|
EXPECT_TRUE(moduleObj.contains("memory_mb"));
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-03-27 12:33:38 -04:00
|
|
|
EXPECT_EQ(moduleObj["name"].get<std::string>(), "test_plugin");
|
|
|
|
|
EXPECT_GE(moduleObj["cpu_percent"].get<double>(), 0.0);
|
|
|
|
|
EXPECT_GE(moduleObj["cpu_time_seconds"].get<double>(), 0.0);
|
|
|
|
|
EXPECT_GE(moduleObj["memory_mb"].get<double>(), 0.0);
|
2026-03-24 16:50:23 -04:00
|
|
|
|
2026-01-22 15:51:03 -05:00
|
|
|
delete[] result;
|
|
|
|
|
}
|