Compare commits

..

1 Commits

Author SHA1 Message Date
linianlin 81b1d99121 AI 自动生成测试用例 2026-06-09 13:35:29 +08:00
6 changed files with 20849 additions and 25708 deletions

View File

@ -1,54 +0,0 @@
# 任务规划系统 (Mission Planning System)
基于 Spring Boot 3.x + Java 17 构建的单体后端工程,实现了从战场事件感知到任务生成、执行监控的闭环管理。
## 技术栈
- **语言**: Java 17
- **框架**: Spring Boot 3.2.5
- **接口文档**: Knife4j 4.5.0 (OpenAPI 3)
- **构建工具**: Maven
- **数据存储**: 内存假数据(预留数据库扩展点)
## 功能模块
| 模块 | 说明 |
|------|------|
| 事件管理 | 事件接收、处理、展示CRUD + 状态变更) |
| 模板管理 | 模板集合接收、版本管理、展示、选择与推荐 |
| 计划管理 | 集中式/分布式计划管理、重配置、HITL通知 |
| 方案分发 | 任务方案分发、ACK响应、重试机制 |
| 状态监控 | 遥测数据接收、异常报警、数据陈旧检测 |
## 启动方式
```bash
# 1. 编译打包
mvn clean package -DskipTests
# 2. 运行
java -jar target/mission-planning-system-1.0.0.jar
# 或直接通过 Maven 启动
mvn spring-boot:run
```
## 接口文档
启动后访问:
- **Swagger 文档**: http://localhost:8080/swagger-ui/index.html
- **Knife4j 文档**: http://localhost:8080/doc.html
## 健康检查
- http://localhost:8080/api/health
## 扩展说明
当前版本使用内存假数据存储(`ConcurrentHashMap`后续可扩展接入达梦DM8或人大金仓KingbaseES数据库。
主要扩展点如下:
- `repository/` 目录预留了 Repository 接口定义
- 各 Service 实现类实现了对应接口,便于切换数据源
- 配置类预留了数据源配置扩展点

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

76
pom.xml
View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>mission-planning-system</artifactId>
<version>1.0.0</version>
<name>Mission Planning System</name>
<description>任务规划系统 - 战场事件感知到任务生成、执行监控的闭环管理平台</description>
<properties>
<java.version>17</java.version>
<knife4j.version>4.5.0</knife4j.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Knife4j + Swagger/OpenAPI -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

25
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.10.0)
project(test_task_plan_execute)
include(FetchContent)
if (MSVC)
add_compile_options(/utf-8)
endif()
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
include(CTest)
enable_testing()
add_executable(test_task_plan_execute test_app.cpp ../src/app.cpp)
target_link_libraries(test_task_plan_execute gtest gmock gtest_main)
include(GoogleTest)
gtest_discover_tests(test_task_plan_execute)

223
tests/test_app.cpp Normal file
View File

@ -0,0 +1,223 @@
#include <gtest/gtest.h>
#include "app.hpp"
#include <thread>
#include <chrono>
using namespace bmp;
// 注意generateId, now, timeToString 为文件内部 static 函数,
// 具有内部链接属性,无法在外部测试文件中直接访问和测试。
// 根据 C++ 单元测试最佳实践及编译错误反馈,移除对它们的直接测试。
TEST(EventServiceTest, testReceiveEventNormal) {
EventService svc;
EXPECT_TRUE(svc.receiveEvent("<event>test</event>"));
}
TEST(EventServiceTest, testSendAckNormal) {
EventService svc;
svc.receiveEvent("<event>test</event>");
auto events = svc.getPendingEvents();
std::string ack = svc.sendAck(events[0].id);
EXPECT_EQ(0, ack.find("ACK:"));
}
TEST(EventServiceTest, testGetRawEventNormal) {
EventService svc;
svc.receiveEvent("<event>test</event>");
auto events = svc.getPendingEvents();
const Event* evt = svc.getRawEvent(events[0].id);
EXPECT_NE(nullptr, evt);
}
TEST(EventServiceTest, testProcessEventNormal) {
EventService svc;
svc.receiveEvent("<event>test</event>");
auto events = svc.getPendingEvents();
EXPECT_TRUE(svc.processEvent(events[0].id));
const Event* evt = svc.getRawEvent(events[0].id);
EXPECT_EQ(EventStatus::PROCESSING, evt->status);
}
TEST(EventServiceTest, testSaveStandardEvent) {
EventService svc;
Event evt;
evt.id = "EVT_001";
evt.status = EventStatus::ACCEPTED;
svc.saveStandardEvent(evt);
const Event* res = svc.getRawEvent("EVT_001");
EXPECT_NE(nullptr, res);
EXPECT_EQ(EventStatus::ACCEPTED, res->status);
}
TEST(EventServiceTest, testQueryEventsFilter) {
EventService svc;
svc.receiveEvent("<event>test</event>");
std::unordered_map<std::string, std::string> filters;
filters["status"] = "PENDING";
auto res = svc.queryEvents(filters);
EXPECT_FALSE(res.empty());
}
TEST(EventServiceTest, testGetPendingEvents) {
EventService svc;
svc.receiveEvent("<event>test</event>");
auto res = svc.getPendingEvents();
EXPECT_FALSE(res.empty());
}
TEST(TemplateServiceTest, testReceiveTemplatesNormal) {
TemplateService svc;
std::string data = "<id>T1</id>\n<name>Template1</name>\n</template>";
size_t count = svc.receiveTemplates(data);
EXPECT_GT(count, 0);
}
TEST(TemplateServiceTest, testGetTemplateList) {
TemplateService svc;
svc.receiveTemplates("<id>T1</id>\n<name>Template1</name>\n</template>");
auto list = svc.getTemplateList();
EXPECT_FALSE(list.empty());
}
TEST(TemplateServiceTest, testSelectTemplateNormal) {
TemplateService svc;
svc.receiveTemplates("<id>T1</id>\n<name>Template1</name>\n</template>");
EXPECT_TRUE(svc.selectTemplate("T1"));
}
TEST(TemplateServiceTest, testRecommendTemplate) {
TemplateService svc;
svc.receiveTemplates("<id>T1</id>\n<name>Template1</name>\n<scenario>RECON</scenario>\n</template>");
std::string rec = svc.recommendTemplate("RECON");
EXPECT_EQ("T1", rec);
}
TEST(TemplateServiceTest, testGetConfig) {
TemplateService svc;
auto cfg = svc.getConfig();
EXPECT_EQ("enabled", cfg["version_check"]);
}
TEST(PlanServiceTest, testGenerateTaskNormal) {
PlanService svc;
std::unordered_map<std::string, std::string> params;
std::string planId = svc.generateTask("EVT1", "TPL1", params);
EXPECT_FALSE(planId.empty());
}
TEST(PlanServiceTest, testSubmitTask) {
PlanService svc;
std::unordered_map<std::string, std::string> params;
std::string planId = svc.generateTask("EVT1", "TPL1", params);
TaskPlan plan = svc.submitTask(planId);
EXPECT_EQ(PlanStatus::CONFIRMED, plan.status);
}
TEST(PlanServiceTest, testGetPlanList) {
PlanService svc;
std::unordered_map<std::string, std::string> params;
svc.generateTask("EVT1", "TPL1", params);
auto list = svc.getPlanList();
EXPECT_FALSE(list.empty());
}
TEST(PlanServiceTest, testSortPlans) {
PlanService svc;
std::unordered_map<std::string, std::string> params;
svc.generateTask("EVT1", "TPL1", params);
std::unordered_map<std::string, int> weights = {{"priority", 1}, {"time", 1}};
EXPECT_NO_THROW(svc.sortPlans(weights));
}
TEST(PlanServiceTest, testReconfigurePlan) {
PlanService svc;
std::unordered_map<std::string, std::string> params;
std::string planId = svc.generateTask("EVT1", "TPL1", params);
std::vector<PlanNode> newNodes;
EXPECT_TRUE(svc.reconfigurePlan(planId, newNodes));
}
TEST(PlanServiceTest, testNotifyHITL) {
PlanService svc;
std::unordered_map<std::string, std::string> params;
std::string planId = svc.generateTask("EVT1", "TPL1", params);
EXPECT_NO_THROW(svc.notifyHITL(planId, "Test message"));
}
TEST(DistributionServiceTest, testDistributePlan) {
DistributionService svc;
auto logs = svc.distributePlan("PLAN1");
EXPECT_EQ(3, logs.size());
}
TEST(DistributionServiceTest, testReceiveAck) {
DistributionService svc;
auto logs = svc.distributePlan("PLAN1");
EXPECT_TRUE(svc.receiveAck(logs[0].logId, DistributionResponse::ACK));
}
TEST(DistributionServiceTest, testUpdateStatus) {
DistributionService svc;
EXPECT_NO_THROW(svc.updateStatus("PLAN1"));
}
TEST(DistributionServiceTest, testGetLogsByPlan) {
DistributionService svc;
svc.distributePlan("PLAN1");
auto logs = svc.getLogsByPlan("PLAN1");
EXPECT_EQ(3, logs.size());
}
TEST(StatusMonitorServiceTest, testReceiveTelemetry) {
StatusMonitorService svc;
std::vector<uint8_t> data(20, 0);
auto log = svc.receiveTelemetry(data);
EXPECT_FALSE(log.assetId.empty());
}
TEST(StatusMonitorServiceTest, testParseDataTooShort) {
StatusMonitorService svc;
std::vector<uint8_t> data(5, 0);
auto log = svc.parseData(data);
EXPECT_TRUE(log.isAbnormal);
}
TEST(StatusMonitorServiceTest, testTriggerAlarm) {
StatusMonitorService svc;
StatusLog log;
log.isAbnormal = true;
log.assetId = "AST_1";
log.detailInfo = "Error";
std::string alarm = svc.triggerAlarm(log);
EXPECT_NE(std::string::npos, alarm.find("[ALARM]"));
}
TEST(StatusMonitorServiceTest, testGetLatestStatus) {
StatusMonitorService svc;
std::vector<uint8_t> data(20, 0);
svc.receiveTelemetry(data);
auto log = svc.getLatestStatus("AST_0");
EXPECT_EQ("AST_0", log.assetId);
}
TEST(StatusMonitorServiceTest, testCheckStaleData) {
StatusMonitorService svc;
std::vector<uint8_t> data(20, 0);
svc.receiveTelemetry(data);
EXPECT_NO_THROW(svc.checkStaleData(0));
}
TEST(BattlefieldMissionPlannerTest, testConstructor) {
EXPECT_NO_THROW(BattlefieldMissionPlanner planner);
}
TEST(BattlefieldMissionPlannerTest, testInitialize) {
BattlefieldMissionPlanner planner;
EXPECT_TRUE(planner.initialize());
}
TEST(BattlefieldMissionPlannerTest, testRun) {
BattlefieldMissionPlanner planner;
EXPECT_NO_THROW(planner.run());
}