Compare commits
1 Commits
main
...
test_20260
| Author | SHA1 | Date |
|---|---|---|
|
|
81b1d99121 |
54
README.md
54
README.md
|
|
@ -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 实现类实现了对应接口,便于切换数据源
|
|
||||||
- 配置类预留了数据源配置扩展点
|
|
||||||
46144
events.ndjson
46144
events.ndjson
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
76
pom.xml
|
|
@ -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>
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue