262 lines
8.5 KiB
C++
262 lines
8.5 KiB
C++
|
|
#include <gtest/gtest.h>
|
||
|
|
#include <gmock/gmock.h>
|
||
|
|
#include "core/event.hpp"
|
||
|
|
#include "core/task.hpp"
|
||
|
|
#include "core/template.hpp"
|
||
|
|
#include "core/plan.hpp"
|
||
|
|
#include "core/dispatch.hpp"
|
||
|
|
#include "core/message_bus.hpp"
|
||
|
|
|
||
|
|
using namespace battlefield;
|
||
|
|
|
||
|
|
// ==================== SU-01 -> SU-02 集成 (事件到任务) ====================
|
||
|
|
TEST(IntegrationTest, EventToTaskFlow) {
|
||
|
|
EventProcessor ep;
|
||
|
|
TaskGenerator tg;
|
||
|
|
tg.SetAutoGenerate(false);
|
||
|
|
|
||
|
|
// 接收威胁事件
|
||
|
|
ep.ReceiveEvent(
|
||
|
|
R"({"eventId":"INT-EVT-001","type":"threat","source":"radar_east","priority":8,"location":"sector-9","message":"敌方导弹发射"})",
|
||
|
|
"radar_east");
|
||
|
|
|
||
|
|
auto events = ep.GetPendingEvents();
|
||
|
|
ASSERT_EQ(events.size(), 1u);
|
||
|
|
|
||
|
|
// 标记为处理中
|
||
|
|
ep.MarkProcessing("INT-EVT-001");
|
||
|
|
|
||
|
|
// 生成任务草案
|
||
|
|
TaskDraft draft = tg.CreateTaskFromEvent(events[0]);
|
||
|
|
EXPECT_EQ(draft.taskType, "THREAT_RESPONSE");
|
||
|
|
EXPECT_EQ(draft.relatedEventId, "INT-EVT-001");
|
||
|
|
|
||
|
|
// 提交草案
|
||
|
|
nlohmann::json submitted = tg.SubmitDraftAsJson(draft.id);
|
||
|
|
EXPECT_EQ(submitted["relatedEventId"], "INT-EVT-001");
|
||
|
|
EXPECT_EQ(submitted["status"], "SUBMITTED");
|
||
|
|
|
||
|
|
// 标记事件已解决
|
||
|
|
ep.MarkResolved("INT-EVT-001");
|
||
|
|
EXPECT_EQ(ep.GetPendingEvents().size(), 0u);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== SU-02 -> SU-04 集成 (任务到方案) ====================
|
||
|
|
TEST(IntegrationTest, TaskToPlanFlow) {
|
||
|
|
TaskGenerator tg;
|
||
|
|
PlanManager pm;
|
||
|
|
|
||
|
|
Event intelEvent;
|
||
|
|
intelEvent.id = "INT-EVT-002";
|
||
|
|
intelEvent.type = EventType::INTEL;
|
||
|
|
intelEvent.priority = 7;
|
||
|
|
intelEvent.location = "sector-3";
|
||
|
|
intelEvent.source = "satellite";
|
||
|
|
|
||
|
|
TaskDraft draft = tg.CreateTaskFromEvent(intelEvent);
|
||
|
|
ASSERT_EQ(draft.taskType, "INTEL_ANALYSIS");
|
||
|
|
|
||
|
|
Plan plan = pm.CreatePlan("情报处理方案-" + draft.id, draft.description);
|
||
|
|
ASSERT_FALSE(plan.id.empty());
|
||
|
|
|
||
|
|
PlanSubTask st{"SUB-1", "", "情报核实", "核实" + draft.title, 0, "intel_team", 45.0, 4};
|
||
|
|
pm.AddSubTask(plan.id, st);
|
||
|
|
|
||
|
|
pm.RecalculateAllScores();
|
||
|
|
EXPECT_GT(pm.GetPlan(plan.id).score, 0.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== SU-03 + SU-04 集成 (模板+方案) ====================
|
||
|
|
TEST(IntegrationTest, TemplateToPlanFlow) {
|
||
|
|
TemplateManager tm;
|
||
|
|
PlanManager pm;
|
||
|
|
|
||
|
|
tm.LoadTemplates("/simulated");
|
||
|
|
auto recommended = tm.RecommendTemplate();
|
||
|
|
ASSERT_FALSE(recommended.versionId.empty());
|
||
|
|
|
||
|
|
Plan plan = pm.CreatePlan("模板方案-" + recommended.name, recommended.description);
|
||
|
|
EXPECT_FALSE(plan.id.empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== SU-04 -> SU-05 集成 (方案到分发) ====================
|
||
|
|
TEST(IntegrationTest, PlanToDispatchFlow) {
|
||
|
|
PlanManager pm;
|
||
|
|
DispatchMonitor dm;
|
||
|
|
|
||
|
|
Plan plan = pm.CreatePlan("突击方案", "正面突击");
|
||
|
|
|
||
|
|
PlanSubTask st1{"INT-ST-1", "", "前沿侦察", "无人机侦察", 1, "recon", 30.0, 3};
|
||
|
|
PlanSubTask st2{"INT-ST-2", "INT-ST-1", "精确打击", "火力覆盖", 2, "strike", 45.0, 8};
|
||
|
|
PlanSubTask st3{"INT-ST-3", "INT-ST-2", "阵地巩固", "防御部署", 3, "infantry", 60.0, 5};
|
||
|
|
pm.AddSubTask(plan.id, st1);
|
||
|
|
pm.AddSubTask(plan.id, st2);
|
||
|
|
pm.AddSubTask(plan.id, st3);
|
||
|
|
|
||
|
|
pm.RecalculateAllScores();
|
||
|
|
|
||
|
|
// 分发
|
||
|
|
plan = pm.GetPlan(plan.id);
|
||
|
|
CmdPacket pkt = dm.DispatchPlan(plan, "battalion-alpha");
|
||
|
|
EXPECT_EQ(pkt.planId, plan.id);
|
||
|
|
EXPECT_EQ(pkt.targetUnit, "battalion-alpha");
|
||
|
|
|
||
|
|
auto status = dm.GetMonitorStatus();
|
||
|
|
EXPECT_EQ(status.totalTasks, 3);
|
||
|
|
|
||
|
|
// 推进
|
||
|
|
dm.AdvanceProgress(3);
|
||
|
|
auto finalStatus = dm.GetMonitorStatus();
|
||
|
|
EXPECT_EQ(finalStatus.completedTasks, 3);
|
||
|
|
EXPECT_DOUBLE_EQ(finalStatus.progressPercent, 100.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== 端到端完整流程 ====================
|
||
|
|
TEST(IntegrationTest, EndToEndFlow) {
|
||
|
|
// SU-01: 事件接收
|
||
|
|
EventProcessor ep;
|
||
|
|
ep.ReceiveEvent(
|
||
|
|
R"({"eventId":"E2E-001","type":"threat","source":"early_warning","priority":9,"location":"zone-hot","message":"敌方大规模集结"})",
|
||
|
|
"early_warning");
|
||
|
|
ep.ReceiveEvent(
|
||
|
|
R"({"eventId":"E2E-002","type":"intel","source":"drone","priority":7,"location":"zone-beta","message":"疑似指挥部"})",
|
||
|
|
"drone");
|
||
|
|
|
||
|
|
auto events = ep.GetPendingEvents();
|
||
|
|
ASSERT_EQ(events.size(), 2u);
|
||
|
|
|
||
|
|
// SU-01 状态流转
|
||
|
|
for (const auto& e : events) {
|
||
|
|
ep.MarkProcessing(e.id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// SU-02: 任务生成
|
||
|
|
TaskGenerator tg;
|
||
|
|
std::vector<TaskDraft> drafts;
|
||
|
|
for (const auto& e : events) {
|
||
|
|
drafts.push_back(tg.CreateTaskFromEvent(e));
|
||
|
|
}
|
||
|
|
ASSERT_EQ(drafts.size(), 2u);
|
||
|
|
|
||
|
|
// SU-03: 模板管理
|
||
|
|
TemplateManager tm;
|
||
|
|
tm.LoadTemplates("/simulated");
|
||
|
|
auto recommended = tm.RecommendTemplate();
|
||
|
|
ASSERT_FALSE(recommended.versionId.empty());
|
||
|
|
|
||
|
|
// SU-04: 方案创建
|
||
|
|
PlanManager pm;
|
||
|
|
Plan plan = pm.CreatePlan("端到端测试方案", "E2E integrated test plan");
|
||
|
|
for (size_t i = 0; i < drafts.size(); ++i) {
|
||
|
|
PlanSubTask st{"E2E-ST-"+std::to_string(i), "", drafts[i].title, drafts[i].description,
|
||
|
|
static_cast<int32_t>(i), "unit-"+std::to_string(i),
|
||
|
|
30.0, drafts[i].priority};
|
||
|
|
pm.AddSubTask(plan.id, st);
|
||
|
|
}
|
||
|
|
pm.RecalculateAllScores();
|
||
|
|
EXPECT_GT(pm.GetPlan(plan.id).score, 0.0);
|
||
|
|
|
||
|
|
// 方案对比
|
||
|
|
Plan plan2 = pm.CreatePlan("备用方案", "backup");
|
||
|
|
std::string cmp = pm.ComparePlans(plan.id, plan2.id);
|
||
|
|
EXPECT_FALSE(cmp.empty());
|
||
|
|
|
||
|
|
// 方案融合
|
||
|
|
Plan merged = pm.MergePlans({plan.id, plan2.id});
|
||
|
|
EXPECT_GT(merged.SubTaskCount(), 0u);
|
||
|
|
|
||
|
|
// SU-05: 分发监控
|
||
|
|
DispatchMonitor dm;
|
||
|
|
plan = pm.GetPlan(plan.id);
|
||
|
|
CmdPacket pkt = dm.DispatchPlan(plan, "command-center");
|
||
|
|
|
||
|
|
auto status = dm.GetMonitorStatus();
|
||
|
|
EXPECT_EQ(status.totalTasks, static_cast<int32_t>(drafts.size()));
|
||
|
|
|
||
|
|
dm.AdvanceProgress(status.totalTasks);
|
||
|
|
auto finalStatus = dm.GetMonitorStatus();
|
||
|
|
EXPECT_DOUBLE_EQ(finalStatus.progressPercent, 100.0);
|
||
|
|
|
||
|
|
// 归档事件
|
||
|
|
for (const auto& e : events) {
|
||
|
|
ep.MarkArchived(e.id);
|
||
|
|
}
|
||
|
|
EXPECT_EQ(ep.GetPendingEvents().size(), 0u);
|
||
|
|
EXPECT_EQ(ep.GetEventsByStatus(EventStatus::ARCHIVED).size(), 2u);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== 消息总线集成 ====================
|
||
|
|
TEST(IntegrationTest, MessageBusEventTaskFlow) {
|
||
|
|
auto& bus = MessageBus::Instance();
|
||
|
|
EventProcessor ep;
|
||
|
|
TaskGenerator tg;
|
||
|
|
tg.SetAutoGenerate(false);
|
||
|
|
|
||
|
|
bool taskCreatedViaBus = false;
|
||
|
|
std::string busDraftId;
|
||
|
|
|
||
|
|
// TaskGenerator 订阅 event.received
|
||
|
|
bus.Subscribe("event.received", [&](const BusMessage& msg) {
|
||
|
|
if (msg.payload.contains("eventId")) {
|
||
|
|
taskCreatedViaBus = true;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
ep.ReceiveEvent(
|
||
|
|
R"({"eventId":"BUS-EVT-001","type":"threat","priority":9,"location":"zone"})",
|
||
|
|
"bus_source");
|
||
|
|
|
||
|
|
bus.Publish("event.received", "SU-01", nlohmann::json::object({{"eventId", "BUS-EVT-001"}}));
|
||
|
|
EXPECT_TRUE(taskCreatedViaBus);
|
||
|
|
|
||
|
|
// 正常生成并提交
|
||
|
|
auto events = ep.GetPendingEvents();
|
||
|
|
ASSERT_EQ(events.size(), 1u);
|
||
|
|
TaskDraft draft = tg.CreateTaskFromEvent(events[0]);
|
||
|
|
nlohmann::json submit = tg.SubmitDraftAsJson(draft.id);
|
||
|
|
EXPECT_FALSE(submit.empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== 反馈闭环集成 ====================
|
||
|
|
TEST(IntegrationTest, FeedbackLoopReplanTrigger) {
|
||
|
|
PlanManager pm;
|
||
|
|
DispatchMonitor dm;
|
||
|
|
|
||
|
|
// 创建并分发一个有多个子任务的方案
|
||
|
|
Plan plan = pm.CreatePlan("反馈测试方案", "test feedback loop");
|
||
|
|
for (int i = 0; i < 10; ++i) {
|
||
|
|
PlanSubTask st{"FB-ST-"+std::to_string(i), "", "Task"+std::to_string(i), "",
|
||
|
|
i, "unit", 10.0, 1};
|
||
|
|
pm.AddSubTask(plan.id, st);
|
||
|
|
}
|
||
|
|
|
||
|
|
plan = pm.GetPlan(plan.id);
|
||
|
|
dm.DispatchPlan(plan, "unit");
|
||
|
|
|
||
|
|
// 高失败率触发重规划
|
||
|
|
EXPECT_FALSE(dm.NeedsReplan());
|
||
|
|
dm.ReportFailure(8); // 80% failure
|
||
|
|
EXPECT_TRUE(dm.NeedsReplan());
|
||
|
|
|
||
|
|
// 响应重规划:创建新方案
|
||
|
|
Plan newPlan = pm.CreatePlan("重规划方案", "响应反馈闭环");
|
||
|
|
int newSubTaskIdx = 0;
|
||
|
|
for (const auto& st : plan.subTasks) {
|
||
|
|
// 跳过已失败任务对应的子任务(简化模拟)
|
||
|
|
if (newSubTaskIdx < 2) { // 只保留前2个
|
||
|
|
PlanSubTask adapted = st;
|
||
|
|
adapted.id = "REPLAN-ST-" + std::to_string(newSubTaskIdx);
|
||
|
|
pm.AddSubTask(newPlan.id, adapted);
|
||
|
|
++newSubTaskIdx;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
pm.RecalculateAllScores();
|
||
|
|
EXPECT_GT(pm.GetPlan(newPlan.id).score, 0.0);
|
||
|
|
|
||
|
|
// 分发新方案
|
||
|
|
dm.ClearReplanFlag();
|
||
|
|
newPlan = pm.GetPlan(newPlan.id);
|
||
|
|
CmdPacket newCmd = dm.DispatchPlan(newPlan, "backup-unit");
|
||
|
|
EXPECT_FALSE(newCmd.packetId.empty());
|
||
|
|
}
|