task_plan_execute/tests/basic_test.cpp

392 lines
14 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.

/**
* @file basic_test.cpp
* @brief 战场任务规划管理系统基本单元测试
*
* 使用标准库 assert 进行单元测试,覆盖核心功能模块:
* - SU-01: 事件接收与处理
* - SU-02: 事件标准化处理
* - SU-03: 事件展示与操作
* - SU-04: 任务生成
* - SU-05: 任务模板管理
* - SU-06: 计划管理
* - SU-07: 方案分发
* - SU-08: 状态监控
*/
#include "app.hpp"
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
using namespace bmp;
/**
* @brief 测试事件接收与处理SU-01
*
* @requirement(name="事件接收与处理", id="SU-01")
* 测试接收有效JSON事件、有效XML事件、空数据和无效数据。
*/
static void testEventReception() {
std::cout << "[测试] SU-01: 事件接收与处理" << std::endl;
EventService svc;
// 测试1: 接收有效JSON事件
std::string jsonEvent = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\" }";
bool result = svc.receiveEvent(jsonEvent);
assert(result && "接收有效JSON事件应该成功");
// 测试2: 接收有效XML事件
std::string xmlEvent = "<event><type>空情预警</type></event>";
result = svc.receiveEvent(xmlEvent);
assert(result && "接收有效XML事件应该成功");
// 测试3: 接收空数据
result = svc.receiveEvent("");
assert(!result && "接收空数据应该失败");
// 测试4: 接收无效数据既不是JSON也不是XML
result = svc.receiveEvent("invalid data without brackets");
assert(!result && "接收无效格式数据应该失败");
// 测试5: 发送ACK
std::string ack = svc.sendAck("unknown");
assert(ack == "ACK:UNKNOWN" && "未知事件ID应返回 UNKNOWN");
std::cout << " SU-01 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试事件标准化处理SU-02
*
* @requirement(name="事件标准化处理", id="SU-02")
* 测试获取原始事件、处理事件和保存标准化事件。
*/
static void testEventStandardization() {
std::cout << "[测试] SU-02: 事件标准化处理" << std::endl;
EventService svc;
// 准备测试数据
std::string jsonEvent = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\" }";
svc.receiveEvent(jsonEvent);
auto pending = svc.getPendingEvents();
assert(!pending.empty() && "应有待处理事件");
// 测试1: 获取原始事件
const Event* raw = svc.getRawEvent(pending[0].id);
assert(raw != nullptr && "应能获取原始事件");
assert(raw->status == EventStatus::PENDING && "原始事件状态应为PENDING");
// 测试2: 处理事件(标准化)
bool processed = svc.processEvent(pending[0].id);
assert(processed && "事件标准化应成功");
// 测试3: 再次处理应失败(状态已变更)
processed = svc.processEvent(pending[0].id);
assert(!processed && "重复处理应失败");
// 测试4: 处理不存在的事件
processed = svc.processEvent("nonexistent");
assert(!processed && "处理不存在的事件应失败");
// 测试5: 保存标准化事件
Event customEvent;
customEvent.id = "CUSTOM_001";
customEvent.title = "测试事件";
customEvent.status = EventStatus::ACCEPTED;
svc.saveStandardEvent(customEvent);
const Event* saved = svc.getRawEvent("CUSTOM_001");
assert(saved != nullptr && "保存后应能获取标准化事件");
assert(saved->status == EventStatus::ACCEPTED && "标准化事件状态应正确");
std::cout << " SU-02 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试事件展示与操作SU-03
*
* @requirement(name="事件展示与操作", id="SU-03")
* 测试事件查询、获取待处理事件等功能。
*/
static void testEventQuery() {
std::cout << "[测试] SU-03: 事件展示与操作" << std::endl;
EventService svc;
// 准备测试数据
svc.receiveEvent("{ \"type\": \"A\" }");
svc.receiveEvent("{ \"type\": \"B\" }");
// 测试1: 查询所有事件
auto all = svc.queryEvents({});
assert(all.size() == 2 && "应有2个事件");
// 测试2: 获取待处理事件
auto pending = svc.getPendingEvents();
assert(pending.size() == 2 && "应有2个待处理事件");
// 测试3: 过滤状态
auto filtered = svc.queryEvents({{"status", "PENDING"}});
assert(filtered.size() == 2 && "过滤PENDING应有2个");
std::cout << " SU-03 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试任务模板管理SU-05
*
* @requirement(name="任务模板管理", id="SU-05")
* 测试模板接收、列表、选择和推荐功能。
*/
static void testTemplateManagement() {
std::cout << "[测试] SU-05: 任务模板管理" << std::endl;
TemplateService svc;
// 测试1: 接收空数据
size_t count = svc.receiveTemplates("");
assert(count == 0 && "空数据应解析出0个模板");
// 测试2: 接收有效模板
std::string tmplData =
"{\"id\":\"T1\",\"name\":\"模板1\",\"scenario\":\"侦察\"}\n"
"{\"id\":\"T2\",\"name\":\"模板2\",\"scenario\":\"预警\"}\n";
count = svc.receiveTemplates(tmplData);
assert(count == 2 && "应有2个模板被解析");
// 测试3: 获取模板列表
auto list = svc.getTemplateList();
assert(list.size() == 2 && "模板列表应有2个");
// 测试4: 选择模板
bool selected = svc.selectTemplate("T1");
assert(selected && "选择存在的模板应成功");
selected = svc.selectTemplate("NONEXIST");
assert(!selected && "选择不存在的模板应失败");
// 测试5: 推荐模板
std::string recommended = svc.recommendTemplate("侦察");
assert(recommended == "T1" && "应为侦察推荐T1模板");
recommended = svc.recommendTemplate("未知");
assert(!recommended.empty() && "无匹配时应有默认推荐");
// 测试6: 获取配置
auto config = svc.getConfig();
assert(config.find("auto_recommend") != config.end() && "应有auto_recommend配置");
std::cout << " SU-05 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试任务生成与计划管理SU-04, SU-06
*
* @requirement(name="任务生成", id="SU-04")
* @requirement(name="计划管理", id="SU-06")
* 测试任务生成、提交、计划列表、排序、重配置和HITL通知。
*/
static void testPlanManagement() {
std::cout << "[测试] SU-04/SU-06: 任务生成与计划管理" << std::endl;
PlanService svc;
// 测试1: 生成任务 - 空参数应失败
std::string planId = svc.generateTask("", "T1", {});
assert(planId.empty() && "空事件ID应生成失败");
// 测试2: 生成任务 - 有效参数
planId = svc.generateTask("EVT_001", "T1", {{"remarks", "测试"}});
assert(!planId.empty() && "有效参数应生成计划");
assert(planId.find("PLAN_") == 0 && "计划ID应以PLAN_开头");
// 测试3: 提交任务
TaskPlan plan = svc.submitTask(planId);
assert(plan.status == PlanStatus::CONFIRMED && "提交后状态应为CONFIRMED");
assert(plan.id == planId && "返回的计划ID应匹配");
// 测试4: 提交不存在的计划
TaskPlan emptyPlan = svc.submitTask("NONEXIST");
assert(emptyPlan.id.empty() && "不存在的计划应返回空");
// 测试5: 获取计划列表
auto plans = svc.getPlanList();
assert(plans.size() == 1 && "应有1个计划");
// 测试6: 排序计划
svc.sortPlans({{"priority", 1}, {"time", 1}});
// 测试7: 计划重配置
std::vector<PlanNode> newNodes;
PlanNode node;
node.nodeId = "NODE_001";
node.planId = planId;
node.taskType = "侦察";
node.executeUnit = "无人机";
newNodes.push_back(node);
bool reconfigured = svc.reconfigurePlan(planId, newNodes);
assert(reconfigured && "重配置应成功");
// 重配置不存在的计划
reconfigured = svc.reconfigurePlan("NONEXIST", newNodes);
assert(!reconfigured && "重配置不存在计划应失败");
// 测试8: HITL通知
svc.notifyHITL(planId, "请确认方案");
svc.notifyHITL("NONEXIST", "测试"); // 不应崩溃
std::cout << " SU-04/SU-06 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试方案分发SU-07
*
* @requirement(name="方案分发", id="SU-07")
* 测试分发流程、ACK接收、重试和状态更新。
*/
static void testDistribution() {
std::cout << "[测试] SU-07: 方案分发" << std::endl;
DistributionService svc;
// 测试1: 分发计划
auto logs = svc.distributePlan("PLAN_001");
assert(logs.size() == 3 && "应有3条分发日志");
for (const auto& log : logs) {
assert(!log.logId.empty() && "日志ID不应为空");
assert(log.response == DistributionResponse::TIMEOUT && "初始状态应为TIMEOUT");
assert(log.retryCount == 0 && "初始重试次数应为0");
}
// 测试2: 接收ACK
bool ackOk = svc.receiveAck(logs[0].logId, DistributionResponse::ACK);
assert(ackOk && "接收ACK应成功");
ackOk = svc.receiveAck("NONEXIST", DistributionResponse::ACK);
assert(!ackOk && "接收不存在的日志ACK应失败");
// 测试3: 接收NACK并验证重试
bool nackOk = svc.receiveAck(logs[1].logId, DistributionResponse::NACK);
assert(nackOk && "接收NACK应成功");
// 测试4: 查询分发日志
auto queriedLogs = svc.getLogsByPlan("PLAN_001");
assert(queriedLogs.size() == 3 && "应有3条日志");
assert(queriedLogs[0].response == DistributionResponse::ACK && "第一条应为ACK");
assert(queriedLogs[1].response == DistributionResponse::NACK && "第二条应为NACK");
// 测试5: 状态更新(不崩溃即可)
svc.updateStatus("PLAN_001");
std::cout << " SU-07 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试状态监控SU-08
*
* @requirement(name="状态监控", id="SU-08")
* 测试遥测数据接收、解析、报警触发和数据陈旧检查。
*/
static void testStatusMonitoring() {
std::cout << "[测试] SU-08: 状态监控" << std::endl;
StatusMonitorService svc;
// 测试1: 接收有效遥测数据
std::vector<uint8_t> validData = {
0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x28,
0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C
};
StatusLog log = svc.receiveTelemetry(validData);
assert(!log.recordId.empty() && "记录ID不应为空");
assert(!log.isAbnormal && "正常状态码不应标记为异常");
// 测试2: 接收异常遥测数据
std::vector<uint8_t> abnormalData = {
0x00, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x38, // 9016 > 9000
0x45, 0x72, 0x72, 0x6F, 0x72
};
StatusLog abnormalLog = svc.receiveTelemetry(abnormalData);
assert(abnormalLog.isAbnormal && "状态码大于9000应标记为异常");
// 测试3: 接收短数据(无效)
std::vector<uint8_t> shortData = {0x00, 0x01};
StatusLog shortLog = svc.receiveTelemetry(shortData);
assert(shortLog.isAbnormal && "短数据应标记为异常");
assert(shortLog.statusCode == "ERR_INVALID_DATA" && "短数据应有错误码");
// 测试4: 触发报警
std::string alarm = svc.triggerAlarm(abnormalLog);
assert(!alarm.empty() && "异常状态应触发报警");
assert(alarm.find("[ALARM]") == 0 && "报警消息应以[ALARM]开头");
// 正常状态不触发报警
alarm = svc.triggerAlarm(log);
assert(alarm.empty() && "正常状态不应触发报警");
// 测试5: 获取最新状态
StatusLog latest = svc.getLatestStatus("AST_65537");
assert(latest.assetId == "AST_65537" && "应返回正确资产的状态");
// 不存在的资产
latest = svc.getLatestStatus("UNKNOWN");
assert(latest.isAbnormal && "不存在的资产应标记异常");
// 测试6: 数据陈旧检查
std::this_thread::sleep_for(std::chrono::milliseconds(50));
svc.checkStaleData(10);
StatusLog staleLog = svc.getLatestStatus("AST_65537");
assert(staleLog.isAbnormal && "超过阈值后应标记为陈旧");
assert(staleLog.statusCode == "STALE" && "陈旧数据状态码应为STALE");
std::cout << " SU-08 测试通过!" << std::endl << std::endl;
}
/**
* @brief 测试系统外观类
*
* @requirement(name="业务目标", id="REQ-BMP-001")
* 测试系统初始化、完整业务流程的协调。
*/
static void testSystemIntegration() {
std::cout << "[测试] BMP集成: 系统外观类" << std::endl;
BattlefieldMissionPlanner bmp;
// 测试1: 初始化
bool initialized = bmp.initialize();
assert(initialized && "系统初始化应成功");
// 测试2: 获取各服务引用
assert(&bmp.getEventService() != nullptr && "事件服务不应为空");
assert(&bmp.getTemplateService() != nullptr && "模板服务不应为空");
assert(&bmp.getPlanService() != nullptr && "计划服务不应为空");
assert(&bmp.getDistributionService() != nullptr && "分发服务不应为空");
assert(&bmp.getStatusMonitorService() != nullptr && "状态监控服务不应为空");
// 测试3: 运行主循环(不崩溃即可)
bmp.run();
std::cout << " BMP集成测试通过" << std::endl << std::endl;
}
int main() {
std::cout << "========================================" << std::endl;
std::cout << " 战场任务规划管理系统 - 单元测试" << std::endl;
std::cout << "========================================" << std::endl << std::endl;
testEventReception();
testEventStandardization();
testEventQuery();
testTemplateManagement();
testPlanManagement();
testDistribution();
testStatusMonitoring();
testSystemIntegration();
std::cout << "========================================" << std::endl;
std::cout << " 全部测试通过!" << std::endl;
std::cout << "========================================" << std::endl;
return 0;
}