NavisworksTransport/UnitTests/Integration/BatchQueueF1ProcessAutomationTests.cs
tian 539e4a9f2c perf: 剖面盒遍历组节点聚合盒剪枝(大型模型 ~1.8 倍提速)
SectionBoxExporter:
- TraverseAndCollect 对非几何节点(组节点)先查聚合包围盒,
  与剖面盒不相交 → 整棵子树跳过(NW BoundingBox 为文档级缓存 O(1),
  已用 Architecture.nwd 2 万节点 + 全厂模型 403MB 验证)
- GetObjectsAndHiddenItems 增加 prune 参数(默认 true,false 供性能对比)

验证(全厂设备模型 403MB,100x100x40 测试盒):
- 剪枝 72.9s vs 无剪枝 129.9s(~1.8 倍)
- 盒内对象/隐藏节点完全一致(3521/80043,正确性无变化)
- Architecture.nwd(2 万节点):273ms vs 580ms(~2.1 倍)
- 集成测试 25/25

测试基础设施:
- export-section-box 端点加 prune 参数 + traversalMs 计时
- bbox-profiling 端点加 enum=false 模式(根盒查询,避免大模型全枚举 10+ 分钟)
- BatchQueueF1ProcessAutomationTests 末尾等待后台批处理完全退出
  (修复 F1 后台任务残留导致后续 BatchQueue_AddItems isExecuting 断言失败)
- batch-queue-status 端点加 isExecuting 字段
2026-08-06 10:28:59 +08:00

95 lines
4.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;
namespace NavisworksTransport.UnitTests.Integration
{
/// <summary>
/// 批处理队列 F1 端到端测试(剖面盒自动检测,副实例多进程)。
///
/// 独立 TestCategoryNavisworksIntegrationF1不进默认全量
/// TestCategory=NavisworksIntegration因为完整 F1 流程
/// (副实例启动 + 剖面盒导出 + 局部模型检测)耗时较长(分钟级)。
///
/// 单独运行:
/// run-integration-tests.bat "TestCategory=NavisworksIntegrationF1"
///
/// 覆盖链路add虚拟物体DetectAllObjects=true→ process触发 F1
/// → 轮询 batch-queue-status 至 Completed → 断言碰撞报告已生成。
/// </summary>
[TestClass]
[TestCategory("NavisworksIntegrationF1")]
public class BatchQueueF1ProcessAutomationTests
{
private const int TestFrameRate = 15;
private const double TestDurationSeconds = 5.0;
[TestMethod]
[Timeout(360000)]
public async Task BatchQueueF1_ProcessQueue_CompletesWithCollisionReport()
{
using (var client = new NavisworksTestAutomationClient())
{
await client.EnsureServiceReadyAsync(TimeSpan.FromSeconds(90)).ConfigureAwait(false);
// 1. 添加虚拟物体队列项F1 剖面盒自动检测DetectAllObjects=true 走副实例)
JObject add = await client.BatchQueueAddAsync(
"自动测试_Ground", TestFrameRate, TestDurationSeconds).ConfigureAwait(false);
Assert.IsTrue(add.Value<bool>("ok"), "添加队列项失败: " + (string)add["error"]);
int itemId = (int)((JObject)add["data"])["itemId"];
Assert.IsTrue(itemId > 0, "队列项 ID 无效");
// 2. 触发后台处理F1
JObject process = await client.BatchQueueProcessAsync().ConfigureAwait(false);
Assert.IsTrue(process.Value<bool>("ok"), "触发批处理失败: " + (string)process["error"]);
// 3. 轮询队列状态直到该 itemId 进入终态Completed/Failed
DateTime deadline = DateTime.UtcNow.AddMinutes(3);
string status = null;
string errorMessage = null;
while (DateTime.UtcNow < deadline)
{
await Task.Delay(5000).ConfigureAwait(false);
JObject statusResp = await client.BatchQueueStatusAsync(10).ConfigureAwait(false);
Assert.IsTrue(statusResp.Value<bool>("ok"), "查询队列状态失败");
var items = (JArray)statusResp["data"]["items"];
var mine = items?.FirstOrDefault(i => (int)i["itemId"] == itemId);
if (mine != null)
{
status = (string)mine["status"];
errorMessage = (string)mine["errorMessage"];
if (status == "Completed" || status == "Failed")
{
break;
}
}
}
Assert.AreEqual(
"Completed",
status,
"F1 批处理未在时限内完成。itemId=" + itemId +
(string.IsNullOrEmpty(errorMessage) ? "" : ",错误: " + errorMessage));
// 等待后台批处理完全退出(避免后台任务残留影响后续测试的 isExecuting 断言)
DateTime exitDeadline = DateTime.UtcNow.AddSeconds(90);
while (DateTime.UtcNow < exitDeadline)
{
JObject statusResp = await client.BatchQueueStatusAsync(1).ConfigureAwait(false);
bool isExecuting = (bool?)statusResp["data"]?["isExecuting"] ?? false;
if (!isExecuting)
{
break;
}
await Task.Delay(2000).ConfigureAwait(false);
}
}
}
}
}