plan_execute_t1/tests/test_app.cpp

457 lines
13 KiB
C++
Raw 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.

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "app.hpp"
#include <string>
#include <vector>
#include <chrono>
using namespace testing;
// ============================================================================
// 测试夹具CmsEngineTest
// ============================================================================
class CmsEngineTest : public ::testing::Test {
protected:
void SetUp() override {
// 初始化引擎
engine = new CmsEngine();
// 准备测试事件
EventRecord event1;
event1.id = "EVT-001";
event1.status = EventStatus::Pending;
event1.priority = 100;
EventRecord event2;
event2.id = "EVT-002";
event2.status = EventStatus::Pending;
event2.priority = 200;
EventRecord event3;
event3.id = "EVT-003";
event3.status = EventStatus::Generated; // 非 Pending 状态
event3.priority = 150;
// 注入测试事件
engine->ingestEvent(event1);
engine->ingestEvent(event2);
engine->ingestEvent(event3);
}
void TearDown() override {
delete engine;
}
CmsEngine* engine;
};
// ============================================================================
// 测试用例processPendingEvents
// ============================================================================
/**
* @brief 测试正常处理待处理事件
*
* 验证 processPendingEvents 能正确处理所有 Pending 状态的事件,
* 并返回正确的处理数量。
*/
TEST_F(CmsEngineTest, testProcessPendingEventsNormal) {
// 执行
size_t processedCount = engine->processPendingEvents();
// 验证:应该有 2 个 Pending 事件被处理
EXPECT_EQ(processedCount, 2);
// 验证事件状态已更新
const EventRecord* evt1 = engine->findEventById("EVT-001");
ASSERT_NE(evt1, nullptr);
EXPECT_EQ(evt1->status, EventStatus::Generated);
const EventRecord* evt2 = engine->findEventById("EVT-002");
ASSERT_NE(evt2, nullptr);
EXPECT_EQ(evt2->status, EventStatus::Generated);
// 验证非 Pending 事件状态不变
const EventRecord* evt3 = engine->findEventById("EVT-003");
ASSERT_NE(evt3, nullptr);
EXPECT_EQ(evt3->status, EventStatus::Generated); // 原本就是 Generated
// 验证生成了对应的 TaskPlan
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_EQ(plans.size(), 2);
// 验证第一个 Plan 的关联事件 ID
EXPECT_EQ(plans[0].relatedEventId, "EVT-001");
EXPECT_EQ(plans[0].type, PlanType::Centralized);
EXPECT_EQ(plans[0].status, PlanStatus::Drafting);
EXPECT_NEAR(plans[0].resourceQuota, 0.5, 0.001);
// 验证第二个 Plan 的关联事件 ID
EXPECT_EQ(plans[1].relatedEventId, "EVT-002");
}
/**
* @brief 测试无待处理事件的情况
*
* 验证当没有 Pending 状态的事件时processPendingEvents 返回 0。
*/
TEST_F(CmsEngineTest, testProcessPendingEventsNoPending) {
// 先处理所有 Pending 事件
engine->processPendingEvents();
// 再次调用,此时没有 Pending 事件
size_t processedCount = engine->processPendingEvents();
// 验证:应该处理 0 个事件
EXPECT_EQ(processedCount, 0);
// 验证 Plan 数量没有增加
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_EQ(plans.size(), 2); // 第一次处理时生成的 2 个
}
/**
* @brief 测试空事件库的情况
*
* 验证当事件库为空时processPendingEvents 返回 0。
*/
TEST_F(CmsEngineTest, testProcessPendingEventsEmptyEvents) {
// 创建一个新的空引擎
CmsEngine emptyEngine;
// 执行
size_t processedCount = emptyEngine.processPendingEvents();
// 验证:应该处理 0 个事件
EXPECT_EQ(processedCount, 0);
// 验证 Plan 列表为空
const std::vector<TaskPlan>& plans = emptyEngine.getAllPlans();
EXPECT_TRUE(plans.empty());
}
/**
* @brief 测试多次调用 processPendingEvents
*
* 验证多次调用不会重复处理已处理的事件。
*/
TEST_F(CmsEngineTest, testProcessPendingEventsMultipleCalls) {
// 第一次调用
size_t firstCount = engine->processPendingEvents();
EXPECT_EQ(firstCount, 2);
// 第二次调用
size_t secondCount = engine->processPendingEvents();
EXPECT_EQ(secondCount, 0); // 没有新的 Pending 事件
// 第三次调用
size_t thirdCount = engine->processPendingEvents();
EXPECT_EQ(thirdCount, 0);
// 验证 Plan 数量始终为 2
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_EQ(plans.size(), 2);
}
// ============================================================================
// 测试用例findEventById
// ============================================================================
/**
* @brief 测试查找已存在的事件
*
* 验证 findEventById 能正确返回已存在的事件指针。
*/
TEST_F(CmsEngineTest, testFindEventByIdExisting) {
// 执行
const EventRecord* evt = engine->findEventById("EVT-001");
// 验证
ASSERT_NE(evt, nullptr);
EXPECT_EQ(evt->id, "EVT-001");
EXPECT_EQ(evt->status, EventStatus::Pending);
EXPECT_EQ(evt->priority, 100);
}
/**
* @brief 测试查找不存在的事件
*
* 验证 findEventById 在查找不存在的事件时返回 nullptr。
*/
TEST_F(CmsEngineTest, testFindEventByIdNonExisting) {
// 执行
const EventRecord* evt = engine->findEventById("NON-EXISTENT");
// 验证
EXPECT_EQ(evt, nullptr);
}
/**
* @brief 测试查找空字符串 ID
*
* 验证 findEventById 在查找空字符串时返回 nullptr。
*/
TEST_F(CmsEngineTest, testFindEventByIdEmptyString) {
// 执行
const EventRecord* evt = engine->findEventById("");
// 验证
EXPECT_EQ(evt, nullptr);
}
/**
* @brief 测试查找特殊字符 ID
*
* 验证 findEventById 能正确处理包含特殊字符的 ID。
*/
TEST_F(CmsEngineTest, testFindEventByIdSpecialChars) {
// 准备包含特殊字符的事件
EventRecord specialEvent;
specialEvent.id = "EVT-@#$%";
specialEvent.status = EventStatus::Pending;
specialEvent.priority = 50;
engine->ingestEvent(specialEvent);
// 执行
const EventRecord* evt = engine->findEventById("EVT-@#$%");
// 验证
ASSERT_NE(evt, nullptr);
EXPECT_EQ(evt->id, "EVT-@#$%");
}
/**
* @brief 测试查找长 ID 字符串
*
* 验证 findEventById 能正确处理超长 ID 字符串。
*/
TEST_F(CmsEngineTest, testFindEventByIdLongString) {
// 准备长 ID 事件
std::string longId = "EVT-" + std::string(1000, 'A');
EventRecord longEvent;
longEvent.id = longId;
longEvent.status = EventStatus::Pending;
longEvent.priority = 75;
engine->ingestEvent(longEvent);
// 执行
const EventRecord* evt = engine->findEventById(longId);
// 验证
ASSERT_NE(evt, nullptr);
EXPECT_EQ(evt->id, longId);
}
/**
* @brief 测试查找后修改事件状态
*
* 验证通过 findEventById 返回的指针可以正确反映事件状态的变化。
*/
TEST_F(CmsEngineTest, testFindEventByIdAfterStatusChange) {
// 先处理事件,改变状态
engine->processPendingEvents();
// 查找事件
const EventRecord* evt = engine->findEventById("EVT-001");
// 验证状态已更新
ASSERT_NE(evt, nullptr);
EXPECT_EQ(evt->status, EventStatus::Generated);
}
// ============================================================================
// 测试用例createTaskPlan
// ============================================================================
/**
* @brief 测试正常创建任务方案
*
* 验证 createTaskPlan 能正确创建有效的任务方案。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanNormal) {
// 准备
TaskPlan plan;
plan.name = "TestPlan-001";
plan.type = PlanType::Centralized;
plan.status = PlanStatus::Drafting;
plan.resourceQuota = 0.8;
plan.constraints = "测试约束";
// 执行
bool result = engine->createTaskPlan(plan);
// 验证
EXPECT_TRUE(result);
// 验证 ID 已被填充
EXPECT_FALSE(plan.id.empty());
EXPECT_THAT(plan.id, StartsWith("ID-"));
// 验证创建时间已被填充
auto now = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::seconds>(now - plan.createTime).count();
EXPECT_LT(diff, 5); // 创建时间应该在 5 秒内
// 验证方案已存入引擎
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_EQ(plans.size(), 1);
EXPECT_EQ(plans[0].name, "TestPlan-001");
EXPECT_EQ(plans[0].id, plan.id);
}
/**
* @brief 测试创建空名称的任务方案
*
* 验证 createTaskPlan 在名称为空时返回 false。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanEmptyName) {
// 准备空名称方案
TaskPlan plan;
plan.name = "";
plan.type = PlanType::Centralized;
plan.status = PlanStatus::Drafting;
// 执行
bool result = engine->createTaskPlan(plan);
// 验证
EXPECT_FALSE(result);
// 验证方案未被加入引擎
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_TRUE(plans.empty());
}
/**
* @brief 测试创建多个任务方案
*
* 验证 createTaskPlan 能连续创建多个方案,且 ID 自增。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanMultiple) {
// 创建第一个方案
TaskPlan plan1;
plan1.name = "Plan-001";
EXPECT_TRUE(engine->createTaskPlan(plan1));
// 创建第二个方案
TaskPlan plan2;
plan2.name = "Plan-002";
EXPECT_TRUE(engine->createTaskPlan(plan2));
// 创建第三个方案
TaskPlan plan3;
plan3.name = "Plan-003";
EXPECT_TRUE(engine->createTaskPlan(plan3));
// 验证方案数量
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_EQ(plans.size(), 3);
// 验证 ID 自增
EXPECT_EQ(plans[0].id, "ID-00001");
EXPECT_EQ(plans[1].id, "ID-00002");
EXPECT_EQ(plans[2].id, "ID-00003");
// 验证名称正确
EXPECT_EQ(plans[0].name, "Plan-001");
EXPECT_EQ(plans[1].name, "Plan-002");
EXPECT_EQ(plans[2].name, "Plan-003");
}
/**
* @brief 测试创建方案后通过 ID 查找
*
* 验证创建方案后可以通过 findPlanById 正确查找。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanAndFindById) {
// 创建方案
TaskPlan plan;
plan.name = "FindablePlan";
plan.type = PlanType::Distributed;
plan.status = PlanStatus::Drafting;
plan.resourceQuota = 0.6;
EXPECT_TRUE(engine->createTaskPlan(plan));
// 通过 ID 查找
const TaskPlan* foundPlan = engine->findPlanById(plan.id);
// 验证
ASSERT_NE(foundPlan, nullptr);
EXPECT_EQ(foundPlan->name, "FindablePlan");
EXPECT_EQ(foundPlan->type, PlanType::Distributed);
EXPECT_EQ(foundPlan->status, PlanStatus::Drafting);
EXPECT_NEAR(foundPlan->resourceQuota, 0.6, 0.001);
}
/**
* @brief 测试创建方案时带有特殊字符名称
*
* 验证 createTaskPlan 能处理包含特殊字符的方案名称。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanSpecialName) {
// 准备特殊名称
TaskPlan plan;
plan.name = "Plan-@#$%^&*()_+";
plan.type = PlanType::Centralized;
plan.status = PlanStatus::Drafting;
// 执行
bool result = engine->createTaskPlan(plan);
// 验证
EXPECT_TRUE(result);
// 验证方案已存入
const std::vector<TaskPlan>& plans = engine->getAllPlans();
EXPECT_EQ(plans.size(), 1);
EXPECT_EQ(plans[0].name, "Plan-@#$%^&*()_+");
}
/**
* @brief 测试创建方案后更新状态
*
* 验证创建方案后可以更新其状态。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanAndUpdateStatus) {
// 创建方案
TaskPlan plan;
plan.name = "UpdatablePlan";
plan.type = PlanType::Centralized;
plan.status = PlanStatus::Drafting;
EXPECT_TRUE(engine->createTaskPlan(plan));
// 更新状态
bool updateResult = engine->updatePlanStatus(plan.id, PlanStatus::Drafting);
EXPECT_TRUE(updateResult);
// 验证状态已更新
const TaskPlan* updatedPlan = engine->findPlanById(plan.id);
ASSERT_NE(updatedPlan, nullptr);
EXPECT_EQ(updatedPlan->status, PlanStatus::Drafting);
}
/**
* @brief 测试创建方案时传入已填充 ID 的方案
*
* 验证 createTaskPlan 会覆盖传入方案的 ID。
*/
TEST_F(CmsEngineTest, testCreateTaskPlanWithPreFilledId) {
// 准备已填充 ID 的方案
TaskPlan plan;
plan.id = "PRE-FILLED-ID";
plan.name = "TestPlan";
plan.type = PlanType::Centralized;
plan.status = PlanStatus::Drafting;
// 执行
bool result = engine->createTaskPlan(plan);
// 验证
EXPECT_TRUE(result);
// 验证 ID 已被覆盖
EXPECT_NE(plan.id, "PRE-FILLED-ID");
EXPECT_THAT(plan.id, StartsWith("ID-"));
}