libdkapture/test/proc-info-test.cpp

1542 lines
33 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd
//
// SPDX-License-Identifier: LGPL-2.1
// This file uses/derives from googletest
// Copyright 2008, Google Inc.
// Licensed under the BSD 3-Clause License
// See NOTICE for full license text
#include "gtest/gtest.h"
#include <vector>
#include <atomic>
#include <chrono>
#include <climits>
#include <set>
#include <sys/sysmacros.h>
#include <sys/stat.h>
#include "dkapture.h"
// 声明proc_info_init函数这是在BUILTIN模式下的入口点
extern int
proc_info_init(int argc, char **argv, DKapture::DKCallback cb, void *ctx);
// 测试常量定义
const std::string TEST_ROOT = "/tmp/proc_info_test_dir";
// 测试回调函数用于接收和验证BPF事件
static std::vector<struct DKapture::DataHdr> captured_events;
static std::atomic<bool> event_received(false);
// 回调函数用于接收BPF事件
static int test_callback(void *ctx, const void *data, size_t data_sz)
{
// 数据验证
if (data == nullptr || data_sz == 0)
{
return -1;
}
// 数据大小检查
if (data_sz < sizeof(struct DKapture::DataHdr))
{
return -1;
}
// 处理事件
const struct DKapture::DataHdr *hdr =
static_cast<const struct DKapture::DataHdr *>(data);
captured_events.push_back(*hdr);
event_received = true;
return 0;
}
// 测试类
class ProcInfoBasicTest : public ::testing::Test
{
protected:
void SetUp() override
{
// 创建测试目录
mkdir(TEST_ROOT.c_str(), 0755);
// 清除之前捕获的事件
captured_events.clear();
event_received = false;
}
void TearDown() override
{
// 清理测试目录
std::string cmd = "rm -rf " + TEST_ROOT;
system(cmd.c_str());
}
// 辅助函数模拟STAT数据事件
void simulateStatEvent(
pid_t pid,
pid_t tgid,
const char *comm,
int state,
pid_t ppid,
unsigned long vsize,
unsigned long rss
)
{
// 创建一个足够大的缓冲区来容纳DataHdr和ProcPidStat
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidStat);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_STAT;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidStat *stat =
reinterpret_cast<struct ProcPidStat *>(hdr->data);
stat->state = state;
stat->ppid = ppid;
stat->vsize = vsize;
stat->rss = rss;
stat->utime = 1000;
stat->stime = 500;
stat->nice = 0;
stat->priority = 20;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟IO数据事件
void simulateIoEvent(
pid_t pid,
pid_t tgid,
const char *comm,
size_t rchar,
size_t wchar,
size_t read_bytes,
size_t write_bytes
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidIo);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_IO;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidIo *io = reinterpret_cast<struct ProcPidIo *>(hdr->data);
io->rchar = rchar;
io->wchar = wchar;
io->read_bytes = read_bytes;
io->write_bytes = write_bytes;
io->syscr = 100;
io->syscw = 50;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟Traffic数据事件
void simulateTrafficEvent(
pid_t pid,
pid_t tgid,
const char *comm,
size_t rbytes,
size_t wbytes
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidTraffic);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_traffic;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidTraffic *traffic =
reinterpret_cast<struct ProcPidTraffic *>(hdr->data);
traffic->rbytes = rbytes;
traffic->wbytes = wbytes;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟STATM数据事件
void simulateStatmEvent(
pid_t pid,
pid_t tgid,
const char *comm,
unsigned long size,
unsigned long resident,
unsigned long shared,
unsigned long text,
unsigned long data
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidStatm);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_STATM;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidStatm *statm =
reinterpret_cast<struct ProcPidStatm *>(hdr->data);
statm->size = size;
statm->resident = resident;
statm->shared = shared;
statm->text = text;
statm->data = data;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟STATUS数据事件
void simulateStatusEvent(
pid_t pid,
pid_t tgid,
const char *comm,
int state,
uid_t uid,
gid_t gid,
pid_t tracer_pid
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidStatus);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_STATUS;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidStatus *status =
reinterpret_cast<struct ProcPidStatus *>(hdr->data);
status->state = state;
status->uid[0] = uid; // uid
status->uid[1] = uid; // euid
status->gid[0] = gid; // gid
status->gid[1] = gid; // egid
status->tracer_pid = tracer_pid;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟SCHEDSTAT数据事件
void simulateSchedstatEvent(
pid_t pid,
pid_t tgid,
const char *comm,
unsigned long long cpu_time,
unsigned long long rq_wait_time,
unsigned long long timeslices
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidSchedstat);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_SCHEDSTAT;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidSchedstat *schedstat =
reinterpret_cast<struct ProcPidSchedstat *>(hdr->data);
schedstat->cpu_time = cpu_time;
schedstat->rq_wait_time = rq_wait_time;
schedstat->timeslices = timeslices;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟FD数据事件
void simulateFdEvent(
pid_t pid,
pid_t tgid,
const char *comm,
int fd,
unsigned long inode,
dev_t dev,
mode_t i_mode
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidFd);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_FD;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidFd *fdinfo =
reinterpret_cast<struct ProcPidFd *>(hdr->data);
fdinfo->fd = fd;
fdinfo->inode = inode;
fdinfo->dev = dev;
fdinfo->i_mode = i_mode;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟NS数据事件
void simulateNsEvent(
pid_t pid,
pid_t tgid,
const char *comm,
unsigned int cgroup,
unsigned int ipc,
unsigned int mnt,
unsigned int net,
unsigned int pid_ns,
unsigned int user
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidNs);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_NS;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidNs *ns = reinterpret_cast<struct ProcPidNs *>(hdr->data);
ns->cgroup = cgroup;
ns->ipc = ipc;
ns->mnt = mnt;
ns->net = net;
ns->pid = pid_ns;
ns->user = user;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
// 辅助函数模拟LOGINUID数据事件
void simulateLoginuidEvent(
pid_t pid,
pid_t tgid,
const char *comm,
uid_t loginuid
)
{
size_t total_size =
sizeof(struct DKapture::DataHdr) + sizeof(struct ProcPidLoginuid);
char *buffer = new char[total_size];
memset(buffer, 0, total_size);
struct DKapture::DataHdr *hdr =
reinterpret_cast<struct DKapture::DataHdr *>(buffer);
hdr->type = DKapture::PROC_PID_LOGINUID;
hdr->dsz = total_size;
hdr->pid = pid;
hdr->tgid = tgid;
strncpy(hdr->comm, comm, sizeof(hdr->comm) - 1);
struct ProcPidLoginuid *loginuid_info =
reinterpret_cast<struct ProcPidLoginuid *>(hdr->data);
loginuid_info->loginuid.val = loginuid;
test_callback(nullptr, buffer, total_size);
delete[] buffer;
}
};
// 测试基本事件处理
TEST_F(ProcInfoBasicTest, EventHandling)
{
// 模拟STAT事件
simulateStatEvent(1000, 1000, "test_process", 1, 999, 102400, 4096);
// 验证事件是否被捕获
EXPECT_TRUE(event_received) << "Event should be received";
EXPECT_EQ(captured_events.size(), 1) << "Should capture one event";
if (!captured_events.empty())
{
const auto &hdr = captured_events[0];
EXPECT_EQ(hdr.type, DKapture::PROC_PID_STAT) << "Event type should be "
"PROC_PID_STAT";
EXPECT_EQ(hdr.pid, 1000) << "Process ID should match";
EXPECT_EQ(hdr.tgid, 1000) << "Thread group ID should match";
EXPECT_STREQ(hdr.comm, "test_process") << "Process name should match";
}
}
// 测试不同类型的数据事件
TEST_F(ProcInfoBasicTest, DifferentDataTypes)
{
// 模拟不同类型的事件
simulateStatEvent(1001, 1001, "proc1", 1, 1, 102400, 4096);
simulateIoEvent(1002, 1002, "proc2", 1024, 512, 2048, 1024);
simulateTrafficEvent(1003, 1003, "proc3", 4096, 2048);
simulateStatmEvent(1004, 1004, "proc4", 1000, 800, 200, 100, 500);
simulateStatusEvent(1005, 1005, "proc5", 1, 1000, 1000, 0);
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 5) << "Should capture five events";
if (captured_events.size() >= 5)
{
// 验证各种类型的事件
EXPECT_EQ(captured_events[0].type, DKapture::PROC_PID_STAT)
<< "First event should be STAT";
EXPECT_EQ(captured_events[1].type, DKapture::PROC_PID_IO) << "Second "
"event "
"should "
"be IO";
EXPECT_EQ(captured_events[2].type, DKapture::PROC_PID_traffic)
<< "Third event should be TRAFFIC";
EXPECT_EQ(captured_events[3].type, DKapture::PROC_PID_STATM)
<< "Fourth event should be STATM";
EXPECT_EQ(captured_events[4].type, DKapture::PROC_PID_STATUS)
<< "Fifth event should be STATUS";
}
}
// 测试多进程信息处理
TEST_F(ProcInfoBasicTest, MultipleProcesses)
{
// 模拟多个进程的STAT数据
for (int i = 1; i <= 10; i++)
{
std::string comm = "proc" + std::to_string(i);
simulateStatEvent(
1000 + i,
1000 + i,
comm.c_str(),
1,
999,
102400,
4096
);
}
// 验证所有事件都被捕获
EXPECT_EQ(captured_events.size(), 10) << "Should capture ten events";
// 验证进程ID是连续的
for (size_t i = 0; i < captured_events.size(); i++)
{
EXPECT_EQ(captured_events[i].pid, 1001 + static_cast<pid_t>(i))
<< "Process ID should be sequential";
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_STAT)
<< "All events should be STAT type";
}
}
// 测试线程信息处理
TEST_F(ProcInfoBasicTest, ThreadHandling)
{
// 模拟主进程和其线程
simulateStatEvent(2000, 2000, "main_proc", 1, 1999, 204800, 8192); // 主进程
simulateStatEvent(2001, 2000, "main_proc", 1, 1999, 204800, 8192); // 线程1
simulateStatEvent(2002, 2000, "main_proc", 1, 1999, 204800, 8192); // 线程2
simulateStatEvent(2003, 2000, "main_proc", 1, 1999, 204800, 8192); // 线程3
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 4) << "Should capture four events";
if (captured_events.size() >= 4)
{
// 验证主进程
EXPECT_EQ(captured_events[0].pid, 2000) << "Main process PID should "
"match";
EXPECT_EQ(captured_events[0].tgid, 2000) << "Main process TGID should "
"match";
// 验证线程
for (int i = 1; i < 4; i++)
{
EXPECT_EQ(captured_events[i].tgid, 2000) << "Thread TGID should "
"match main process";
EXPECT_NE(captured_events[i].pid, 2000) << "Thread PID should "
"differ from main "
"process";
}
}
}
// 测试IO统计
TEST_F(ProcInfoBasicTest, IoStatistics)
{
// 模拟不同IO模式的进程
simulateIoEvent(
3001,
3001,
"reader",
1024 * 1024,
0,
1024 * 1024,
0
); // 只读进程
simulateIoEvent(
3002,
3002,
"writer",
0,
1024 * 1024,
0,
1024 * 1024
); // 只写进程
simulateIoEvent(
3003,
3003,
"rw_proc",
512 * 1024,
512 * 1024,
256 * 1024,
256 * 1024
); // 读写进程
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 3) << "Should capture three events";
if (captured_events.size() >= 3)
{
// 验证都是IO类型
for (size_t i = 0; i < 3; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_IO)
<< "All events should be IO type";
}
}
}
// 测试网络流量统计
TEST_F(ProcInfoBasicTest, NetworkTrafficStats)
{
// 模拟不同网络使用模式的进程
simulateTrafficEvent(
4001,
4001,
"server",
1024 * 1024,
512 * 1024
); // 服务器:收多发少
simulateTrafficEvent(
4002,
4002,
"client",
512 * 1024,
1024 * 1024
); // 客户端:发多收少
simulateTrafficEvent(
4003,
4003,
"p2p",
2048 * 1024,
2048 * 1024
); // P2P收发相等
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 3) << "Should capture three events";
if (captured_events.size() >= 3)
{
// 验证都是TRAFFIC类型
for (size_t i = 0; i < 3; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_traffic)
<< "All events should be TRAFFIC type";
}
}
}
// 测试内存统计
TEST_F(ProcInfoBasicTest, MemoryStatistics)
{
// 模拟不同内存使用模式的进程
simulateStatmEvent(
5001,
5001,
"small_proc",
1000,
800,
200,
100,
500
); // 小内存进程
simulateStatmEvent(
5002,
5002,
"large_proc",
10000,
8000,
2000,
1000,
5000
); // 大内存进程
simulateStatmEvent(
5003,
5003,
"shared_proc",
5000,
4000,
3000,
500,
1500
); // 共享内存多的进程
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 3) << "Should capture three events";
if (captured_events.size() >= 3)
{
// 验证都是STATM类型
for (size_t i = 0; i < 3; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_STATM)
<< "All events should be STATM type";
}
}
}
// 测试进程状态
TEST_F(ProcInfoBasicTest, ProcessStates)
{
// 模拟不同状态的进程
simulateStatusEvent(6001, 6001, "running", 0, 1000, 1000, 0); // 运行状态
simulateStatusEvent(6002, 6002, "sleeping", 1, 1001, 1001, 0); // 睡眠状态
simulateStatusEvent(
6003,
6003,
"stopped",
4,
1002,
1002,
6004
); // 停止状态,有跟踪器
simulateStatusEvent(6004, 6004, "zombie", 16, 1003, 1003, 0); // 僵尸状态
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 4) << "Should capture four events";
if (captured_events.size() >= 4)
{
// 验证都是STATUS类型
for (size_t i = 0; i < 4; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_STATUS)
<< "All events should be STATUS type";
}
}
}
// 测试调度统计
TEST_F(ProcInfoBasicTest, SchedulerStatistics)
{
// 模拟不同调度特征的进程
simulateSchedstatEvent(
7001,
7001,
"cpu_intensive",
1000000000ULL,
10000000ULL,
1000
); // CPU密集型
simulateSchedstatEvent(
7002,
7002,
"io_wait",
100000000ULL,
500000000ULL,
5000
); // IO等待多
simulateSchedstatEvent(
7003,
7003,
"interactive",
200000000ULL,
50000000ULL,
10000
); // 交互式
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 3) << "Should capture three events";
if (captured_events.size() >= 3)
{
// 验证都是SCHEDSTAT类型
for (size_t i = 0; i < 3; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_SCHEDSTAT)
<< "All events should be SCHEDSTAT type";
}
}
}
// 测试文件描述符
TEST_F(ProcInfoBasicTest, FileDescriptors)
{
// 模拟不同类型的文件描述符
simulateFdEvent(
8001,
8001,
"fd_test",
0,
12345,
makedev(8, 1),
S_IFREG | 0644
); // 常规文件
simulateFdEvent(
8001,
8001,
"fd_test",
1,
0,
makedev(5, 0),
S_IFCHR | 0666
); // 字符设备 (stdout)
simulateFdEvent(
8001,
8001,
"fd_test",
2,
0,
makedev(5, 0),
S_IFCHR | 0666
); // 字符设备 (stderr)
simulateFdEvent(
8001,
8001,
"fd_test",
3,
54321,
makedev(0, 15),
S_IFSOCK | 0777
); // 套接字
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 4) << "Should capture four events";
if (captured_events.size() >= 4)
{
// 验证都是FD类型
for (size_t i = 0; i < 4; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_FD)
<< "All events should be FD type";
EXPECT_EQ(captured_events[i].pid, 8001) << "All FDs should belong "
"to same process";
}
}
}
// 测试命名空间
TEST_F(ProcInfoBasicTest, Namespaces)
{
// 模拟不同命名空间配置的进程
simulateNsEvent(
9001,
9001,
"host_proc",
4026531835U,
4026531839U,
4026531840U,
4026531993U,
4026531836U,
4026531837U
); // 主机命名空间
simulateNsEvent(
9002,
9002,
"container",
4026532000U,
4026532001U,
4026532002U,
4026532003U,
4026532004U,
4026532005U
); // 容器命名空间
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 2) << "Should capture two events";
if (captured_events.size() >= 2)
{
// 验证都是NS类型
for (size_t i = 0; i < 2; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_NS)
<< "All events should be NS type";
}
}
}
// 测试错误处理
TEST_F(ProcInfoBasicTest, ErrorHandling)
{
// 测试空数据
int result = test_callback(nullptr, nullptr, 0);
EXPECT_EQ(result, -1) << "Null data should be rejected";
// 清除之前的事件
captured_events.clear();
event_received = false;
// 测试数据大小不足
char small_data[1];
result = test_callback(nullptr, small_data, sizeof(small_data));
EXPECT_EQ(result, -1) << "Incomplete data should be rejected";
// 验证没有事件被捕获
EXPECT_FALSE(event_received) << "No event should be received for invalid "
"data";
EXPECT_EQ(captured_events.size(), 0) << "No events should be captured for "
"invalid data";
}
// 测试边界条件
TEST_F(ProcInfoBasicTest, BoundaryConditions)
{
// 测试极大进程ID
simulateStatEvent(
INT_MAX,
INT_MAX,
"max_pid",
1,
INT_MAX - 1,
ULONG_MAX,
ULONG_MAX
);
// 测试最小进程ID
simulateStatEvent(1, 1, "min_pid", 1, 0, 0, 0);
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 2) << "Should capture two events";
if (captured_events.size() >= 2)
{
// 验证极大PID
EXPECT_EQ(captured_events[0].pid, INT_MAX) << "Max PID should match";
// 验证最小PID
EXPECT_EQ(captured_events[1].pid, 1) << "Min PID should match";
}
}
// 测试性能
TEST_F(ProcInfoBasicTest, Performance)
{
// 清除之前捕获的事件
captured_events.clear();
event_received = false;
// 记录开始时间
auto start_time = std::chrono::high_resolution_clock::now();
// 模拟大量事件
const int NUM_EVENTS = 1000;
for (int i = 0; i < NUM_EVENTS; i++)
{
std::string comm = "perf_test_" + std::to_string(i);
simulateStatEvent(
10000 + i,
10000 + i,
comm.c_str(),
1,
9999,
102400,
4096
);
}
// 记录结束时间
auto end_time = std::chrono::high_resolution_clock::now();
// 计算处理时间
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end_time - start_time
);
// 输出性能指标
std::cout << "Processing " << NUM_EVENTS << " events took "
<< duration.count() << " microseconds" << std::endl;
std::cout << "Average time per event: "
<< static_cast<double>(duration.count()) / NUM_EVENTS
<< " microseconds" << std::endl;
// 验证所有事件都被处理
EXPECT_EQ(captured_events.size(), NUM_EVENTS) << "All events should be "
"processed";
// 验证处理时间是否在合理范围内
EXPECT_LT(duration.count(), 1000000) << "Event processing should be "
"reasonably fast";
}
// 测试混合数据类型
TEST_F(ProcInfoBasicTest, MixedDataTypes)
{
// 为同一个进程模拟多种类型的数据
pid_t test_pid = 11000;
const char *test_comm = "mixed_test";
simulateStatEvent(
test_pid,
test_pid,
test_comm,
1,
test_pid - 1,
204800,
8192
);
simulateIoEvent(test_pid, test_pid, test_comm, 2048, 1024, 4096, 2048);
simulateTrafficEvent(test_pid, test_pid, test_comm, 8192, 4096);
simulateStatmEvent(
test_pid,
test_pid,
test_comm,
2000,
1600,
400,
200,
1000
);
simulateStatusEvent(test_pid, test_pid, test_comm, 1, 1000, 1000, 0);
simulateSchedstatEvent(
test_pid,
test_pid,
test_comm,
500000000ULL,
25000000ULL,
2000
);
simulateFdEvent(
test_pid,
test_pid,
test_comm,
0,
98765,
makedev(8, 1),
S_IFREG | 0644
);
simulateNsEvent(
test_pid,
test_pid,
test_comm,
4026531835U,
4026531839U,
4026531840U,
4026531993U,
4026531836U,
4026531837U
);
// 验证所有事件都被捕获
EXPECT_EQ(captured_events.size(), 8) << "Should capture eight events";
if (captured_events.size() >= 8)
{
// 验证所有事件都属于同一个进程
for (size_t i = 0; i < captured_events.size(); i++)
{
EXPECT_EQ(captured_events[i].pid, test_pid) << "All events should "
"belong to same "
"process";
EXPECT_STREQ(captured_events[i].comm, test_comm) << "All events "
"should have "
"same comm";
}
// 验证数据类型的多样性
std::set<DKapture::DataType> types;
for (const auto &event : captured_events)
{
types.insert(event.type);
}
EXPECT_EQ(types.size(), 8) << "Should have 8 different data types";
}
}
// 测试LOGINUID数据类型
TEST_F(ProcInfoBasicTest, LoginuidHandling)
{
// 模拟不同loginuid的进程
simulateLoginuidEvent(12001, 12001, "user_proc", 1000); // 普通用户进程
simulateLoginuidEvent(12002, 12002, "root_proc", 0); // root进程
simulateLoginuidEvent(
12003,
12003,
"daemon_proc",
65535
); // 守护进程(无登录用户)
// 验证事件是否被捕获
EXPECT_EQ(captured_events.size(), 3) << "Should capture three events";
if (captured_events.size() >= 3)
{
// 验证都是LOGINUID类型
for (size_t i = 0; i < 3; i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_LOGINUID)
<< "All events should be LOGINUID type";
}
}
}
// 测试进程状态转换
TEST_F(ProcInfoBasicTest, ProcessStateTransitions)
{
pid_t test_pid = 13000;
const char *test_comm = "state_test";
// 模拟进程状态变化序列:运行->睡眠->停止->僵尸
simulateStatusEvent(
test_pid,
test_pid,
test_comm,
0,
1000,
1000,
0
); // 运行
simulateStatusEvent(
test_pid,
test_pid,
test_comm,
1,
1000,
1000,
0
); // 睡眠
simulateStatusEvent(
test_pid,
test_pid,
test_comm,
4,
1000,
1000,
0
); // 停止
simulateStatusEvent(
test_pid,
test_pid,
test_comm,
16,
1000,
1000,
0
); // 僵尸
// 验证状态转换序列
EXPECT_EQ(captured_events.size(), 4) << "Should capture four state "
"transitions";
if (captured_events.size() >= 4)
{
// 验证所有事件都属于同一个进程
for (const auto &event : captured_events)
{
EXPECT_EQ(event.pid, test_pid) << "All events should belong to "
"same process";
}
}
}
// 测试系统级进程监控
TEST_F(ProcInfoBasicTest, SystemProcessMonitoring)
{
// 模拟系统关键进程
simulateStatEvent(1, 1, "systemd", 1, 0, 1024 * 1024, 4096); // init进程
simulateStatEvent(2, 0, "kthreadd", 1, 0, 0, 0); // 内核线程
simulateStatEvent(3, 0, "migration/0", 1, 2, 0, 0); // 迁移线程
simulateStatEvent(4, 0, "rcu_gp", 1, 2, 0, 0); // RCU线程
simulateStatEvent(5, 0, "rcu_par_gp", 1, 2, 0, 0); // RCU并行线程
// 验证系统进程监控
EXPECT_EQ(captured_events.size(), 5) << "Should capture five system "
"processes";
if (captured_events.size() >= 5)
{
// 验证init进程
EXPECT_EQ(captured_events[0].pid, 1) << "First process should be init";
EXPECT_STREQ(captured_events[0].comm, "systemd") << "Init process "
"should be systemd";
// 验证内核线程特征
for (size_t i = 1; i < captured_events.size(); i++)
{
EXPECT_EQ(captured_events[i].tgid, 0) << "Kernel threads should "
"have tgid 0";
}
}
}
// 测试内存压力场景
TEST_F(ProcInfoBasicTest, MemoryPressureScenarios)
{
// 模拟内存压力下的进程
simulateStatmEvent(
14001,
14001,
"heavy_mem",
100000,
95000,
10000,
1000,
85000
); // 高内存使用
simulateStatmEvent(
14002,
14002,
"shared_heavy",
50000,
45000,
40000,
2000,
8000
); // 高共享内存
simulateStatmEvent(
14003,
14003,
"text_heavy",
30000,
25000,
5000,
20000,
5000
); // 大代码段
simulateStatmEvent(
14004,
14004,
"data_heavy",
80000,
75000,
5000,
5000,
70000
); // 大数据段
// 验证内存使用模式
EXPECT_EQ(captured_events.size(), 4) << "Should capture four "
"memory-intensive processes";
if (captured_events.size() >= 4)
{
// 验证都是STATM类型
for (const auto &event : captured_events)
{
EXPECT_EQ(event.type, DKapture::PROC_PID_STATM) << "All events "
"should be "
"STATM type";
}
}
}
// 测试高频IO操作
TEST_F(ProcInfoBasicTest, HighFrequencyIO)
{
// 模拟高频IO的进程
simulateIoEvent(
15001,
15001,
"db_server",
1024 * 1024 * 100,
1024 * 1024 * 50,
1024 * 1024 * 80,
1024 * 1024 * 40
);
simulateIoEvent(
15002,
15002,
"log_writer",
1024 * 100,
1024 * 1024 * 200,
1024 * 50,
1024 * 1024 * 180
);
simulateIoEvent(
15003,
15003,
"backup_tool",
1024 * 1024 * 500,
1024 * 1024 * 500,
1024 * 1024 * 450,
1024 * 1024 * 450
);
// 验证高频IO处理
EXPECT_EQ(captured_events.size(), 3) << "Should capture three high-IO "
"processes";
if (captured_events.size() >= 3)
{
// 验证IO类型和数据量
for (const auto &event : captured_events)
{
EXPECT_EQ(event.type, DKapture::PROC_PID_IO) << "All events should "
"be IO type";
}
}
}
// 测试网络密集型应用
TEST_F(ProcInfoBasicTest, NetworkIntensiveApplications)
{
// 模拟网络密集型应用
simulateTrafficEvent(
16001,
16001,
"web_server",
1024UL * 1024 * 1024,
1024UL * 1024 * 512
); // Web服务器
simulateTrafficEvent(
16002,
16002,
"proxy",
1024UL * 1024 * 1024,
1024UL * 1024 * 1024
); // 代理服务器
simulateTrafficEvent(
16003,
16003,
"cdn_cache",
1024UL * 1024 * 2048,
1024UL * 1024 * 1024
); // CDN缓存
simulateTrafficEvent(
16004,
16004,
"stream_srv",
1024UL * 1024 * 512,
1024UL * 1024 * 2048
); // 流媒体服务
// 验证网络流量处理
EXPECT_EQ(captured_events.size(), 4) << "Should capture four "
"network-intensive processes";
if (captured_events.size() >= 4)
{
// 验证流量类型
for (const auto &event : captured_events)
{
EXPECT_EQ(event.type, DKapture::PROC_PID_traffic) << "All events "
"should be "
"TRAFFIC type";
}
}
}
// 测试调度器行为分析
TEST_F(ProcInfoBasicTest, SchedulerBehaviorAnalysis)
{
// 模拟不同调度特征的进程
simulateSchedstatEvent(
17001,
17001,
"rt_task",
2000000000ULL,
1000000ULL,
100
); // 实时任务
simulateSchedstatEvent(
17002,
17002,
"batch_job",
5000000000ULL,
100000000ULL,
50
); // 批处理任务
simulateSchedstatEvent(
17003,
17003,
"interactive",
500000000ULL,
10000000ULL,
5000
); // 交互任务
simulateSchedstatEvent(
17004,
17004,
"idle_task",
100000000ULL,
800000000ULL,
10
); // 空闲任务
// 验证调度统计
EXPECT_EQ(captured_events.size(), 4) << "Should capture four different "
"scheduling patterns";
if (captured_events.size() >= 4)
{
// 验证调度类型
for (const auto &event : captured_events)
{
EXPECT_EQ(event.type, DKapture::PROC_PID_SCHEDSTAT) << "All events "
"should be "
"SCHEDSTAT "
"type";
}
}
}
// 测试容器化环境
TEST_F(ProcInfoBasicTest, ContainerizedEnvironment)
{
// 模拟容器化环境的进程
simulateNsEvent(
18001,
18001,
"container1",
4026532100U,
4026532101U,
4026532102U,
4026532103U,
4026532104U,
4026532105U
); // 容器1命名空间
simulateNsEvent(
18002,
18002,
"container2",
4026532200U,
4026532201U,
4026532202U,
4026532203U,
4026532204U,
4026532205U
); // 容器2命名空间
simulateNsEvent(
18003,
18003,
"host_proc",
4026531835U,
4026531839U,
4026531840U,
4026531993U,
4026531836U,
4026531837U
); // 主机进程
// 验证容器化环境
EXPECT_EQ(captured_events.size(), 3) << "Should capture three "
"containerized processes";
if (captured_events.size() >= 3)
{
// 验证命名空间类型
for (const auto &event : captured_events)
{
EXPECT_EQ(event.type, DKapture::PROC_PID_NS) << "All events should "
"be NS type";
}
}
}
// 测试文件描述符泄漏检测
TEST_F(ProcInfoBasicTest, FileDescriptorLeakDetection)
{
pid_t leak_pid = 19000;
const char *leak_comm = "fd_leak_test";
// 模拟文件描述符逐渐增加的场景
for (int i = 3; i < 100; i += 10)
{
simulateFdEvent(
leak_pid,
leak_pid,
leak_comm,
i,
10000 + i,
makedev(8, 1),
S_IFREG | 0644
);
}
// 验证文件描述符监控
EXPECT_EQ(captured_events.size(), 10) << "Should capture ten file "
"descriptor events";
if (captured_events.size() >= 10)
{
// 验证文件描述符递增
for (size_t i = 0; i < captured_events.size(); i++)
{
EXPECT_EQ(captured_events[i].type, DKapture::PROC_PID_FD)
<< "All events should be FD type";
EXPECT_EQ(captured_events[i].pid, leak_pid) << "All FDs should "
"belong to same "
"process";
}
}
}
// 测试进程生命周期完整追踪
TEST_F(ProcInfoBasicTest, CompleteProcessLifecycleTracking)
{
pid_t lifecycle_pid = 20000;
const char *lifecycle_comm = "lifecycle_test";
// 模拟进程完整生命周期
// 1. 进程启动 - STAT事件
simulateStatEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
0,
1000,
102400,
4096
);
// 2. 初始内存分配 - STATM事件
simulateStatmEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
1000,
800,
200,
100,
500
);
// 3. 开始IO操作 - IO事件
simulateIoEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
1024,
512,
2048,
1024
);
// 4. 网络通信 - TRAFFIC事件
simulateTrafficEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
4096,
2048
);
// 5. 进程状态变更 - STATUS事件
simulateStatusEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
1,
1000,
1000,
0
);
// 6. 调度统计 - SCHEDSTAT事件
simulateSchedstatEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
1000000000ULL,
10000000ULL,
1000
);
// 7. 文件操作 - FD事件
simulateFdEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
0,
12345,
makedev(8, 1),
S_IFREG | 0644
);
// 8. 命名空间信息 - NS事件
simulateNsEvent(
lifecycle_pid,
lifecycle_pid,
lifecycle_comm,
4026531835U,
4026531839U,
4026531840U,
4026531993U,
4026531836U,
4026531837U
);
// 9. 登录用户信息 - LOGINUID事件
simulateLoginuidEvent(lifecycle_pid, lifecycle_pid, lifecycle_comm, 1000);
// 验证完整生命周期追踪
EXPECT_EQ(captured_events.size(), 9) << "Should capture complete process "
"lifecycle";
if (captured_events.size() >= 9)
{
// 验证所有事件都属于同一个进程
for (const auto &event : captured_events)
{
EXPECT_EQ(event.pid, lifecycle_pid) << "All events should belong "
"to same process";
EXPECT_STREQ(event.comm, lifecycle_comm) << "All events should "
"have same comm";
}
// 验证数据类型的完整性
std::set<DKapture::DataType> lifecycle_types;
for (const auto &event : captured_events)
{
lifecycle_types.insert(event.type);
}
EXPECT_EQ(lifecycle_types.size(), 9) << "Should have 9 different data "
"types in lifecycle";
}
}