* 新增 ControllerClientCompatOptions.ConfigRoot 及解析方法 * 兼容层默认从运行目录 Config 加载模型、轨迹和配置 * 移除隐式父工作区根目录推断,旧路径仅在显式配置时生效 * Host 项目编译时将 Config 目录复制到输出目录 * 请求响应日志中间件忽略 /api/status/snapshot 高频轮询 * 补充 ConfigRoot 和日志过滤相关单元测试
149 lines
5.3 KiB
C#
149 lines
5.3 KiB
C#
using Flyshot.ControllerClientCompat;
|
||
using Flyshot.Core.Config;
|
||
|
||
namespace Flyshot.Core.Tests;
|
||
|
||
/// <summary>
|
||
/// 验证 ControllerClient 兼容层默认围绕运行目录 Config 读写配置和轨迹文件。
|
||
/// </summary>
|
||
public sealed class ControllerClientCompatConfigRootTests
|
||
{
|
||
/// <summary>
|
||
/// 验证路径兼容层优先命中运行目录 Config 下的 RobotConfig.json,而不是旧仓库根目录候选。
|
||
/// </summary>
|
||
[Fact]
|
||
public void PathCompatibility_ResolvesRuntimeConfigBeforeLegacyCandidates()
|
||
{
|
||
var runtimeRoot = CreateTempDirectory();
|
||
try
|
||
{
|
||
var configPath = Path.Combine(runtimeRoot, "Config", "RobotConfig.json");
|
||
var legacyPath = Path.Combine(runtimeRoot, "RobotConfig.json");
|
||
Directory.CreateDirectory(Path.GetDirectoryName(configPath)!);
|
||
File.WriteAllText(configPath, "{}");
|
||
File.WriteAllText(legacyPath, "{}");
|
||
|
||
var resolved = PathCompatibility.ResolveConfigPath("RobotConfig.json", runtimeRoot);
|
||
|
||
Assert.Equal(configPath, resolved);
|
||
}
|
||
finally
|
||
{
|
||
Directory.Delete(runtimeRoot, recursive: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证机器人目录优先从显式 ConfigRoot/Models 加载 .robot 文件。
|
||
/// </summary>
|
||
[Fact]
|
||
public void ControllerClientCompatRobotCatalog_LoadsModelFromConfigRootModels()
|
||
{
|
||
var configRoot = CreateTempConfigRoot();
|
||
try
|
||
{
|
||
CopySampleRobotModel(configRoot);
|
||
var options = new ControllerClientCompatOptions { ConfigRoot = configRoot };
|
||
var catalog = new ControllerClientCompatRobotCatalog(options, new RobotModelLoader());
|
||
|
||
var profile = catalog.LoadProfile("FANUC_LR_Mate_200iD");
|
||
|
||
Assert.Equal(Path.Combine(configRoot, "Models", "LR_Mate_200iD_7L.robot"), profile.ModelPath);
|
||
}
|
||
finally
|
||
{
|
||
Directory.Delete(configRoot, recursive: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证 JSON 轨迹存储保存、加载和删除都落在 ConfigRoot/TrajectoryStore 目录。
|
||
/// </summary>
|
||
[Fact]
|
||
public void JsonFlyshotTrajectoryStore_PersistsTrajectoriesUnderConfigRootStore()
|
||
{
|
||
var configRoot = CreateTempConfigRoot();
|
||
try
|
||
{
|
||
var options = new ControllerClientCompatOptions { ConfigRoot = configRoot };
|
||
var store = new JsonFlyshotTrajectoryStore(options, new RobotConfigLoader());
|
||
var settings = new CompatibilityRobotSettings(
|
||
useDo: true,
|
||
ioAddresses: [7, 8],
|
||
ioKeepCycles: 2,
|
||
accLimitScale: 1.0,
|
||
jerkLimitScale: 1.0,
|
||
adaptIcspTryNum: 5);
|
||
var trajectory = TestRobotFactory.CreateUploadedTrajectoryWithSingleShot();
|
||
|
||
store.Save("FANUC_LR_Mate_200iD", settings, trajectory);
|
||
var expectedPath = Path.Combine(configRoot, "TrajectoryStore", "FANUC_LR_Mate_200iD_trajectories.json");
|
||
|
||
Assert.True(File.Exists(expectedPath), $"应在运行目录 Config 下创建轨迹文件: {expectedPath}");
|
||
var loaded = store.LoadAll("FANUC_LR_Mate_200iD", out var loadedSettings);
|
||
Assert.NotNull(loadedSettings);
|
||
Assert.Contains(trajectory.Name, loaded);
|
||
|
||
store.Delete("FANUC_LR_Mate_200iD", trajectory.Name);
|
||
|
||
var afterDelete = store.LoadAll("FANUC_LR_Mate_200iD", out _);
|
||
Assert.Empty(afterDelete);
|
||
}
|
||
finally
|
||
{
|
||
Directory.Delete(configRoot, recursive: true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试专用的运行目录 Config 根,避免污染真实输出目录。
|
||
/// </summary>
|
||
private static string CreateTempConfigRoot()
|
||
{
|
||
var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"), "Config");
|
||
Directory.CreateDirectory(root);
|
||
return root;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建测试专用的临时目录。
|
||
/// </summary>
|
||
private static string CreateTempDirectory()
|
||
{
|
||
var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"));
|
||
Directory.CreateDirectory(root);
|
||
return root;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复制仓库内已固化的现场机器人模型到临时 Config/Models 目录。
|
||
/// </summary>
|
||
private static void CopySampleRobotModel(string configRoot)
|
||
{
|
||
var modelDir = Path.Combine(configRoot, "Models");
|
||
Directory.CreateDirectory(modelDir);
|
||
File.Copy(
|
||
Path.Combine(GetReplacementRoot(), "Config", "Models", "LR_Mate_200iD_7L.robot"),
|
||
Path.Combine(modelDir, "LR_Mate_200iD_7L.robot"));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 定位 replacement 仓库根目录,供测试读取仓库内固化样本。
|
||
/// </summary>
|
||
private static string GetReplacementRoot()
|
||
{
|
||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||
while (current is not null)
|
||
{
|
||
if (File.Exists(Path.Combine(current.FullName, "FlyshotReplacement.sln")))
|
||
{
|
||
return current.FullName;
|
||
}
|
||
|
||
current = current.Parent;
|
||
}
|
||
|
||
throw new DirectoryNotFoundException("Unable to locate the flyshot replacement root.");
|
||
}
|
||
}
|