fix(adminui): dedup + chunk the rename script-scan OR-chain
This commit is contained in:
+80
-1
@@ -43,11 +43,12 @@ public sealed class RawTreeServiceRenameWarningTests
|
||||
private const string EquipmentName = "packer-1";
|
||||
private const string ScriptName = "AreaCalc";
|
||||
|
||||
private static (RawTreeService Service, string DbName) Seeded()
|
||||
private static (RawTreeService Service, string DbName) Seeded(Action<OtOpcUaConfigDbContext>? extra = null)
|
||||
{
|
||||
var name = $"rawwarn-{Guid.NewGuid():N}";
|
||||
using var db = CreateNamed(name);
|
||||
Seed(db);
|
||||
extra?.Invoke(db);
|
||||
return (new RawTreeService(new NamedFactory(name)), name);
|
||||
}
|
||||
|
||||
@@ -124,6 +125,84 @@ public sealed class RawTreeServiceRenameWarningTests
|
||||
result.Warnings.ShouldContain(w => w.Contains("script") && w.Contains(ScriptName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Duplicate_old_paths_are_deduplicated_before_the_scan()
|
||||
{
|
||||
// Two tags share a name under the same device, so both resolve to the SAME old RawPath — the scan
|
||||
// must not carry the duplicate into its predicate, and the warning must still name the script once.
|
||||
var (service, dbName) = Seeded(db =>
|
||||
{
|
||||
db.Tags.Add(new Tag
|
||||
{
|
||||
TagId = "TAG-flow-dup",
|
||||
DeviceId = DevAllId,
|
||||
TagGroupId = null,
|
||||
Name = "flow",
|
||||
DataType = "Float",
|
||||
AccessLevel = TagAccessLevel.Read,
|
||||
TagConfig = "{}",
|
||||
});
|
||||
db.SaveChanges();
|
||||
});
|
||||
var rv = DeviceRowVersion(dbName, DevAllId);
|
||||
|
||||
var result = await service.RenameDeviceAsync(DevAllId, "Dev-renamed", rv);
|
||||
|
||||
result.Ok.ShouldBeTrue();
|
||||
var scriptWarnings = result.Warnings.Where(w => w.Contains("script")).ToList();
|
||||
scriptWarnings.Count.ShouldBe(1);
|
||||
scriptWarnings[0].ShouldBe(
|
||||
$"1 script ('{ScriptName}') references a tag beneath this node by its raw path; " +
|
||||
"the reference will break unless the script is updated.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task A_rename_with_more_paths_than_one_batch_still_finds_matches_in_every_batch()
|
||||
{
|
||||
// 401 affected tags → three scan batches at the 200-term cap. One script names a path in the first
|
||||
// batch, one in the middle, one in the last: a loop that drops any batch loses a name.
|
||||
const int bulkTags = 401;
|
||||
var (service, dbName) = Seeded(db =>
|
||||
{
|
||||
db.Devices.Add(new Device { DeviceId = "DEV-bulk", DriverInstanceId = DriverId, Name = "Dev-bulk", DeviceConfig = "{}" });
|
||||
for (var i = 0; i < bulkTags; i++)
|
||||
{
|
||||
db.Tags.Add(new Tag
|
||||
{
|
||||
TagId = $"TAG-bulk-{i:D3}",
|
||||
DeviceId = "DEV-bulk",
|
||||
TagGroupId = null,
|
||||
Name = $"bulk-{i:D3}",
|
||||
DataType = "Float",
|
||||
AccessLevel = TagAccessLevel.Read,
|
||||
TagConfig = "{}",
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var (scriptName, index) in new[] { ("S-first", 0), ("S-middle", 200), ("S-last", bulkTags - 1) })
|
||||
{
|
||||
db.Scripts.Add(new Script
|
||||
{
|
||||
ScriptId = $"SC-{scriptName}",
|
||||
Name = scriptName,
|
||||
SourceCode = $"var v = ctx.GetTag(\"Plant/modbus-1/Dev-bulk/bulk-{index:D3}\"); return v;",
|
||||
SourceHash = $"hash-{scriptName}",
|
||||
});
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
});
|
||||
var rv = DeviceRowVersion(dbName, "DEV-bulk");
|
||||
|
||||
var result = await service.RenameDeviceAsync("DEV-bulk", "Dev-bulk2", rv);
|
||||
|
||||
result.Ok.ShouldBeTrue();
|
||||
// Ordinal sort: 'S-first' < 'S-last' < 'S-middle'.
|
||||
result.Warnings.ShouldContain(
|
||||
"3 scripts ('S-first', 'S-last', 'S-middle') reference tags beneath this node by their raw " +
|
||||
"paths; the references will break unless the scripts are updated.");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------ Seed
|
||||
|
||||
private static void Seed(OtOpcUaConfigDbContext db)
|
||||
|
||||
Reference in New Issue
Block a user