CounterDroneBackend/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs
tian 5c2b95d777 perf: FrameDataStore 改为内存缓存+结束时批量写入
RecordFrame: 仅内存追加, 零磁盘IO

Flush: 仿真Stop时单次事务批量InsertAll

BeginRecording/Discard/BufferedFrameCount 新API

SimulationEngine: 移除 _frameDb 持久连接, RecordFrames默认true

SimulationRunner: 移除所有 Debug.Log 每帧日志

ReplayController: 适配 ReadFrames 新API

FrameDataStoreTests: 6项覆盖 录制/刷新/读取/丢弃/清理
2026-06-15 18:25:21 +08:00

105 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using CounterDrone.Core;
using CounterDrone.Core.Models;
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);
}
private void CreateFakeDb(string taskId)
{
_store.BeginRecording(taskId);
_store.RecordFrame(0, 0f, new List<EntitySnapshot> { new EntitySnapshot { EntityId = "d1" } });
_store.Flush();
}
[Fact]
public void CleanupExpired_DeletesOldFiles()
{
_store.RetentionDays = 0;
CreateFakeDb("task_old_1");
CreateFakeDb("task_old_2");
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;
CreateFakeDb("task_new");
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()
{
Assert.Equal(0, _store.CleanupExpired());
}
[Fact]
public void RecordAndFlush_ThenReadFrames()
{
_store.BeginRecording("task_rw");
var snapshots = new List<EntitySnapshot>
{
new EntitySnapshot { EntityId = "d1", EntityType = Models.EntityType.Drone, PosX = 100 },
};
_store.RecordFrame(0, 0f, snapshots);
_store.RecordFrame(1, 0.05f, snapshots);
_store.RecordFrame(2, 0.10f, snapshots);
_store.Flush();
var frames = _store.ReadFrames("task_rw", 1, 2);
Assert.Equal(2, frames.Count);
Assert.Equal(1, frames[0].FrameIndex);
Assert.Equal(2, frames[1].FrameIndex);
}
[Fact]
public void Flush_EmptyBuffer_DoesNothing()
{
_store.BeginRecording("task_empty");
_store.Flush(); // no crash
Assert.False(File.Exists(Path.Combine(_testDir, "frames", "task_empty.db")));
}
[Fact]
public void Discard_ClearsBuffer()
{
_store.BeginRecording("task_discard");
_store.RecordFrame(0, 0f, new List<EntitySnapshot> { new EntitySnapshot { EntityId = "d1" } });
_store.Discard();
Assert.Equal(0, _store.BufferedFrameCount);
}
}
}