Phase 7: TTL清理 + 边界测试(空部署/强风/超长航路), 122测试9秒完成
This commit is contained in:
parent
6a86a33e79
commit
60b5e8d952
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using CounterDrone.Core.Models;
|
||||
@ -8,6 +9,8 @@ namespace CounterDrone.Core.Simulation
|
||||
public class FrameDataStore
|
||||
{
|
||||
private readonly IPathProvider _paths;
|
||||
/// <summary>帧数据保留天数,默认 180 天(6 个月)</summary>
|
||||
public int RetentionDays { get; set; } = 180;
|
||||
|
||||
public FrameDataStore(IPathProvider paths)
|
||||
{
|
||||
@ -58,5 +61,28 @@ namespace CounterDrone.Core.Simulation
|
||||
var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db");
|
||||
if (File.Exists(dbPath)) File.Delete(dbPath);
|
||||
}
|
||||
|
||||
/// <summary>清理过期的帧数据库文件</summary>
|
||||
/// <returns>被删除的文件数量</returns>
|
||||
public int CleanupExpired()
|
||||
{
|
||||
var dir = _paths.GetFramesDir();
|
||||
if (!Directory.Exists(dir)) return 0;
|
||||
|
||||
var cutoff = DateTime.Now.AddDays(-RetentionDays);
|
||||
var deleted = 0;
|
||||
|
||||
foreach (var file in Directory.GetFiles(dir, "*.db"))
|
||||
{
|
||||
var creationTime = File.GetCreationTime(file);
|
||||
if (creationTime < cutoff)
|
||||
{
|
||||
File.Delete(file);
|
||||
deleted++;
|
||||
}
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
47
test/reports/喷气拦截_20260611_083136.md
Normal file
47
test/reports/喷气拦截_20260611_083136.md
Normal file
@ -0,0 +1,47 @@
|
||||
# 仿真评估报告
|
||||
|
||||
**任务名称**:喷气拦截
|
||||
**任务编号**:SIM-20260611-004
|
||||
**仿真耗时**:106.4 秒
|
||||
|
||||
## 一、仿真前 — 我方配置
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| 目标数量 | 1 |
|
||||
| 发射平台 | 6 台 |
|
||||
| 探测设备 | 1 台 |
|
||||
| 气溶胶类型 | ActiveMaterial |
|
||||
|
||||
## 二、仿真中 — 关键事件时序
|
||||
|
||||
| 时间(s) | 事件 | 描述 |
|
||||
|---------|------|------|
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_1 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_2 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_3 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_4 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_5 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_6 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 106.4 | DroneDestroyed | 无人机 drone_1 被摧毁 |
|
||||
| 106.4 | SimulationEnd | |
|
||||
|
||||
## 三、仿真后 — 数据统计
|
||||
|
||||
| 统计项 | 值 |
|
||||
|--------|-----|
|
||||
| 无人机总数 | 1 |
|
||||
| 被摧毁 | 1 |
|
||||
| 到达目标 | 0 |
|
||||
| 侵入管控区 | 0 |
|
||||
| 弹药发射次数 | 6 |
|
||||
| 云团生成次数 | 6 |
|
||||
|
||||
**对抗结果**:成功拦截
|
||||
|
||||
47
test/reports/喷气拦截_20260611_083213.md
Normal file
47
test/reports/喷气拦截_20260611_083213.md
Normal file
@ -0,0 +1,47 @@
|
||||
# 仿真评估报告
|
||||
|
||||
**任务名称**:喷气拦截
|
||||
**任务编号**:SIM-20260611-003
|
||||
**仿真耗时**:106.4 秒
|
||||
|
||||
## 一、仿真前 — 我方配置
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| 目标数量 | 1 |
|
||||
| 发射平台 | 6 台 |
|
||||
| 探测设备 | 1 台 |
|
||||
| 气溶胶类型 | ActiveMaterial |
|
||||
|
||||
## 二、仿真中 — 关键事件时序
|
||||
|
||||
| 时间(s) | 事件 | 描述 |
|
||||
|---------|------|------|
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_1 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_2 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_3 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_4 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_5 |
|
||||
| 92.2 | MunitionLaunched | 计划发射 mun_6 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 101.8 | CloudGenerated | 云团生成 |
|
||||
| 106.4 | DroneDestroyed | 无人机 drone_1 被摧毁 |
|
||||
| 106.4 | SimulationEnd | |
|
||||
|
||||
## 三、仿真后 — 数据统计
|
||||
|
||||
| 统计项 | 值 |
|
||||
|--------|-----|
|
||||
| 无人机总数 | 1 |
|
||||
| 被摧毁 | 1 |
|
||||
| 到达目标 | 0 |
|
||||
| 侵入管控区 | 0 |
|
||||
| 弹药发射次数 | 6 |
|
||||
| 云团生成次数 | 6 |
|
||||
|
||||
**对抗结果**:成功拦截
|
||||
|
||||
46
test/reports/活塞拦截_20260611_083140.md
Normal file
46
test/reports/活塞拦截_20260611_083140.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 仿真评估报告
|
||||
|
||||
**任务名称**:活塞拦截
|
||||
**任务编号**:SIM-20260611-041
|
||||
**仿真耗时**:185.6 秒
|
||||
|
||||
## 一、仿真前 — 我方配置
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| 目标数量 | 1 |
|
||||
| 发射平台 | 5 台 |
|
||||
| 探测设备 | 1 台 |
|
||||
| 气溶胶类型 | InertGas |
|
||||
|
||||
## 二、仿真中 — 关键事件时序
|
||||
|
||||
| 时间(s) | 事件 | 描述 |
|
||||
|---------|------|------|
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_1 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_2 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_3 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_4 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_5 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 |
|
||||
| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 |
|
||||
| 185.6 | SimulationEnd | |
|
||||
|
||||
## 三、仿真后 — 数据统计
|
||||
|
||||
| 统计项 | 值 |
|
||||
|--------|-----|
|
||||
| 无人机总数 | 1 |
|
||||
| 被摧毁 | 2 |
|
||||
| 到达目标 | 0 |
|
||||
| 侵入管控区 | 0 |
|
||||
| 弹药发射次数 | 5 |
|
||||
| 云团生成次数 | 5 |
|
||||
|
||||
**对抗结果**:成功拦截
|
||||
|
||||
46
test/reports/活塞拦截_20260611_083216.md
Normal file
46
test/reports/活塞拦截_20260611_083216.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 仿真评估报告
|
||||
|
||||
**任务名称**:活塞拦截
|
||||
**任务编号**:SIM-20260611-041
|
||||
**仿真耗时**:185.6 秒
|
||||
|
||||
## 一、仿真前 — 我方配置
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| 目标数量 | 1 |
|
||||
| 发射平台 | 5 台 |
|
||||
| 探测设备 | 1 台 |
|
||||
| 气溶胶类型 | InertGas |
|
||||
|
||||
## 二、仿真中 — 关键事件时序
|
||||
|
||||
| 时间(s) | 事件 | 描述 |
|
||||
|---------|------|------|
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_1 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_2 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_3 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_4 |
|
||||
| 167.4 | MunitionLaunched | 计划发射 mun_5 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 177.0 | CloudGenerated | 云团生成 |
|
||||
| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 |
|
||||
| 185.6 | DroneDestroyed | 无人机 drone_1 被摧毁 |
|
||||
| 185.6 | SimulationEnd | |
|
||||
|
||||
## 三、仿真后 — 数据统计
|
||||
|
||||
| 统计项 | 值 |
|
||||
|--------|-----|
|
||||
| 无人机总数 | 1 |
|
||||
| 被摧毁 | 2 |
|
||||
| 到达目标 | 0 |
|
||||
| 侵入管控区 | 0 |
|
||||
| 弹药发射次数 | 5 |
|
||||
| 云团生成次数 | 5 |
|
||||
|
||||
**对抗结果**:成功拦截
|
||||
|
||||
164
test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs
Normal file
164
test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs
Normal file
@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using CounterDrone.Core;
|
||||
using CounterDrone.Core.Algorithms;
|
||||
using CounterDrone.Core.Models;
|
||||
using CounterDrone.Core.Repository;
|
||||
using CounterDrone.Core.Services;
|
||||
using CounterDrone.Core.Simulation;
|
||||
using Xunit;
|
||||
|
||||
namespace CounterDrone.Core.Tests
|
||||
{
|
||||
/// <summary>边界场景测试</summary>
|
||||
public class EdgeCaseTests : IDisposable
|
||||
{
|
||||
private readonly string _testDir;
|
||||
private readonly IScenarioService _scenario;
|
||||
private readonly SQLite.SQLiteConnection _db;
|
||||
private string _taskId = string.Empty;
|
||||
|
||||
public EdgeCaseTests()
|
||||
{
|
||||
_testDir = Path.Combine(Path.GetTempPath(), $"cd_edge_{Guid.NewGuid():N}");
|
||||
var paths = new TestPathProvider(_testDir);
|
||||
var dbm = new DatabaseManager(paths);
|
||||
_db = dbm.OpenMainDb();
|
||||
|
||||
_db.Insert(new AmmunitionSpec
|
||||
{
|
||||
AerosolType = (int)AerosolType.InertGas, InitialRadius = 50,
|
||||
CoreDensity = 1.0, DispersionRateBase = 5, MaxRadius = 500,
|
||||
MaxDuration = 120, EffectiveConcentration = 0.05,
|
||||
});
|
||||
|
||||
_scenario = new ScenarioService(
|
||||
new SimTaskRepository(_db), new CombatSceneRepository(_db),
|
||||
new ControlZoneRepository(_db), new TargetConfigRepository(_db),
|
||||
new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db),
|
||||
new RoutePlanRepository(_db), new WaypointRepository(_db));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_db?.Close();
|
||||
if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyDeployment_EngineRunsWithoutCrash()
|
||||
{
|
||||
var task = _scenario.CreateTask("空部署", "");
|
||||
_taskId = task.Id;
|
||||
|
||||
_scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 });
|
||||
_scenario.SaveTarget(_taskId, new TargetConfig
|
||||
{
|
||||
TargetType = (int)TargetType.Piston, Quantity = 1,
|
||||
TypicalSpeed = 100, TypicalAltitude = 300,
|
||||
});
|
||||
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
|
||||
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
|
||||
_scenario.SaveRoute(_taskId, new RoutePlan { FormationMode = (int)FormationMode.Single },
|
||||
new List<Waypoint>
|
||||
{
|
||||
new Waypoint { PosX = 0, PosY = 300, PosZ = 0 },
|
||||
new Waypoint { PosX = 1000, PosY = 300, PosZ = 0 },
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
var r = engine.Tick(1f / 20f);
|
||||
if (r.State == SimulationState.Completed) break;
|
||||
}
|
||||
engine.Stop();
|
||||
|
||||
Assert.Equal(DroneStatus.ReachedTarget, engine.Drones[0].Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtremeWind_DroneStillFlies()
|
||||
{
|
||||
var task = _scenario.CreateTask("飓风", "");
|
||||
_taskId = task.Id;
|
||||
|
||||
_scenario.SaveScene(_taskId, new CombatScene
|
||||
{
|
||||
WindSpeed = 30, // 最大风速
|
||||
WindDirection = (int)WindDirection.E,
|
||||
});
|
||||
_scenario.SaveTarget(_taskId, new TargetConfig
|
||||
{
|
||||
TargetType = (int)TargetType.Piston, Quantity = 1,
|
||||
TypicalSpeed = 600, // 高速对抗强风
|
||||
});
|
||||
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
|
||||
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
|
||||
_scenario.SaveRoute(_taskId, new RoutePlan { FormationMode = (int)FormationMode.Single },
|
||||
new List<Waypoint>
|
||||
{
|
||||
new Waypoint { PosX = 0, PosY = 300, PosZ = 0 },
|
||||
new Waypoint { PosX = 5000, PosY = 300, PosZ = 0 },
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
var r = engine.Tick(1f / 20f);
|
||||
if (r.State == SimulationState.Completed) break;
|
||||
}
|
||||
engine.Stop();
|
||||
|
||||
// 强风下应偏移到东方(+X)
|
||||
Assert.True(engine.Drones[0].PosX > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LongRoute_CompletesWithoutError()
|
||||
{
|
||||
var task = _scenario.CreateTask("超长航路", "");
|
||||
_taskId = task.Id;
|
||||
|
||||
_scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 });
|
||||
_scenario.SaveTarget(_taskId, new TargetConfig
|
||||
{
|
||||
TargetType = (int)TargetType.HighSpeed, Quantity = 1,
|
||||
TypicalSpeed = 500,
|
||||
});
|
||||
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
|
||||
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
|
||||
|
||||
// 500 km/h, 100km 航程
|
||||
_scenario.SaveRoute(_taskId, new RoutePlan { FormationMode = (int)FormationMode.Single },
|
||||
new List<Waypoint>
|
||||
{
|
||||
new Waypoint { PosX = 0, PosY = 500, PosZ = 0 },
|
||||
new Waypoint { PosX = 100000, PosY = 500, PosZ = 0 },
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
for (int i = 0; i < 5000; i++)
|
||||
{
|
||||
var r = engine.Tick(1f / 20f);
|
||||
if (r.State == SimulationState.Completed) break;
|
||||
}
|
||||
engine.Stop();
|
||||
|
||||
Assert.Equal(DroneStatus.ReachedTarget, engine.Drones[0].Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs
Normal file
72
test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using CounterDrone.Core;
|
||||
using CounterDrone.Core.Simulation;
|
||||
using Xunit;
|
||||
|
||||
namespace CounterDrone.Core.Tests
|
||||
{
|
||||
public class FrameDataStoreTests : IDisposable
|
||||
{
|
||||
private readonly string _testDir;
|
||||
private readonly FrameDataStore _store;
|
||||
|
||||
public FrameDataStoreTests()
|
||||
{
|
||||
_testDir = Path.Combine(Path.GetTempPath(), $"cd_frames_{Guid.NewGuid():N}");
|
||||
var paths = new TestPathProvider(_testDir);
|
||||
_store = new FrameDataStore(paths);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CleanupExpired_DeletesOldFiles()
|
||||
{
|
||||
// 设置为 0 天保留,所有文件都是"过期"的
|
||||
_store.RetentionDays = 0;
|
||||
|
||||
// 创建一些假帧数据库
|
||||
var db1 = _store.CreateOrOpen("task_old_1");
|
||||
db1.Close();
|
||||
var db2 = _store.CreateOrOpen("task_old_2");
|
||||
db2.Close();
|
||||
|
||||
var deleted = _store.CleanupExpired();
|
||||
Assert.Equal(2, deleted);
|
||||
|
||||
// 文件应该被删除
|
||||
Assert.False(File.Exists(Path.Combine(_testDir, "frames", "task_old_1.db")));
|
||||
Assert.False(File.Exists(Path.Combine(_testDir, "frames", "task_old_2.db")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CleanupExpired_KeepsRecentFiles()
|
||||
{
|
||||
_store.RetentionDays = 365; // 保留 1 年
|
||||
|
||||
var db = _store.CreateOrOpen("task_new");
|
||||
db.Close();
|
||||
|
||||
// 手动修改创建时间为"最近"
|
||||
var filePath = Path.Combine(_testDir, "frames", "task_new.db");
|
||||
File.SetCreationTime(filePath, DateTime.Now);
|
||||
|
||||
var deleted = _store.CleanupExpired();
|
||||
Assert.Equal(0, deleted);
|
||||
|
||||
// 文件应该保留
|
||||
Assert.True(File.Exists(filePath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CleanupExpired_EmptyDir_ReturnsZero()
|
||||
{
|
||||
var deleted = _store.CleanupExpired();
|
||||
Assert.Equal(0, deleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user