173 lines
6.4 KiB
C#
173 lines
6.4 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
|
|
using ZB.MOM.WW.OtOpcUa.Server.OpcUa;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Server.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class EquipmentNamespaceContentLoaderTests : IDisposable
|
|
{
|
|
private const string DriverId = "galaxy-prod";
|
|
private const string OtherDriverId = "galaxy-dev";
|
|
private const long Gen = 5;
|
|
|
|
private readonly OtOpcUaConfigDbContext _db;
|
|
private readonly EquipmentNamespaceContentLoader _loader;
|
|
|
|
public EquipmentNamespaceContentLoaderTests()
|
|
{
|
|
var options = new DbContextOptionsBuilder<OtOpcUaConfigDbContext>()
|
|
.UseInMemoryDatabase($"eq-content-loader-{Guid.NewGuid():N}")
|
|
.Options;
|
|
_db = new OtOpcUaConfigDbContext(options);
|
|
_loader = new EquipmentNamespaceContentLoader(_db);
|
|
}
|
|
|
|
public void Dispose() => _db.Dispose();
|
|
|
|
[Fact]
|
|
public async Task Returns_Null_When_Driver_Has_No_Equipment_At_Generation()
|
|
{
|
|
var result = await _loader.LoadAsync(DriverId, Gen, CancellationToken.None);
|
|
result.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Loads_Areas_Lines_Equipment_Tags_For_Driver_At_Generation()
|
|
{
|
|
SeedBaseline();
|
|
|
|
var result = await _loader.LoadAsync(DriverId, Gen, CancellationToken.None);
|
|
|
|
result.ShouldNotBeNull();
|
|
result!.Areas.ShouldHaveSingleItem().UnsAreaId.ShouldBe("area-1");
|
|
result.Lines.ShouldHaveSingleItem().UnsLineId.ShouldBe("line-a");
|
|
result.Equipment.Count.ShouldBe(2);
|
|
result.Equipment.ShouldContain(e => e.EquipmentId == "eq-oven-3");
|
|
result.Equipment.ShouldContain(e => e.EquipmentId == "eq-press-7");
|
|
result.Tags.Count.ShouldBe(2);
|
|
result.Tags.ShouldContain(t => t.TagId == "tag-temp");
|
|
result.Tags.ShouldContain(t => t.TagId == "tag-press");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Skips_Other_Drivers_Equipment()
|
|
{
|
|
SeedBaseline();
|
|
|
|
// Equipment + Tag owned by a different driver at the same generation — must not leak.
|
|
_db.Equipment.Add(new Equipment
|
|
{
|
|
EquipmentRowId = Guid.NewGuid(), GenerationId = Gen,
|
|
EquipmentId = "eq-other", EquipmentUuid = Guid.NewGuid(),
|
|
DriverInstanceId = OtherDriverId, UnsLineId = "line-a", Name = "other-eq",
|
|
MachineCode = "MC-other",
|
|
});
|
|
_db.Tags.Add(new Tag
|
|
{
|
|
TagRowId = Guid.NewGuid(), GenerationId = Gen, TagId = "tag-other",
|
|
DriverInstanceId = OtherDriverId, EquipmentId = "eq-other",
|
|
Name = "OtherTag", DataType = "Int32",
|
|
AccessLevel = TagAccessLevel.ReadWrite, TagConfig = "plcaddr-other",
|
|
});
|
|
await _db.SaveChangesAsync();
|
|
|
|
var result = await _loader.LoadAsync(DriverId, Gen, CancellationToken.None);
|
|
|
|
result.ShouldNotBeNull();
|
|
result!.Equipment.ShouldNotContain(e => e.EquipmentId == "eq-other");
|
|
result.Tags.ShouldNotContain(t => t.TagId == "tag-other");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Skips_Other_Generations()
|
|
{
|
|
SeedBaseline();
|
|
|
|
// Same driver, different generation — must not leak in. Walker consumes one sealed
|
|
// generation per bootstrap per decision #148.
|
|
_db.Equipment.Add(new Equipment
|
|
{
|
|
EquipmentRowId = Guid.NewGuid(), GenerationId = 99,
|
|
EquipmentId = "eq-futuristic", EquipmentUuid = Guid.NewGuid(),
|
|
DriverInstanceId = DriverId, UnsLineId = "line-a", Name = "futuristic",
|
|
MachineCode = "MC-fut",
|
|
});
|
|
await _db.SaveChangesAsync();
|
|
|
|
var result = await _loader.LoadAsync(DriverId, Gen, CancellationToken.None);
|
|
|
|
result.ShouldNotBeNull();
|
|
result!.Equipment.ShouldNotContain(e => e.EquipmentId == "eq-futuristic");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Skips_Disabled_Equipment()
|
|
{
|
|
SeedBaseline();
|
|
|
|
_db.Equipment.Add(new Equipment
|
|
{
|
|
EquipmentRowId = Guid.NewGuid(), GenerationId = Gen,
|
|
EquipmentId = "eq-disabled", EquipmentUuid = Guid.NewGuid(),
|
|
DriverInstanceId = DriverId, UnsLineId = "line-a", Name = "disabled-eq",
|
|
MachineCode = "MC-dis", Enabled = false,
|
|
});
|
|
await _db.SaveChangesAsync();
|
|
|
|
var result = await _loader.LoadAsync(DriverId, Gen, CancellationToken.None);
|
|
|
|
result.ShouldNotBeNull();
|
|
result!.Equipment.ShouldNotContain(e => e.EquipmentId == "eq-disabled");
|
|
}
|
|
|
|
private void SeedBaseline()
|
|
{
|
|
_db.UnsAreas.Add(new UnsArea
|
|
{
|
|
UnsAreaRowId = Guid.NewGuid(), UnsAreaId = "area-1", ClusterId = "c-warsaw",
|
|
Name = "warsaw", GenerationId = Gen,
|
|
});
|
|
_db.UnsLines.Add(new UnsLine
|
|
{
|
|
UnsLineRowId = Guid.NewGuid(), UnsLineId = "line-a", UnsAreaId = "area-1",
|
|
Name = "line-a", GenerationId = Gen,
|
|
});
|
|
_db.Equipment.AddRange(
|
|
new Equipment
|
|
{
|
|
EquipmentRowId = Guid.NewGuid(), GenerationId = Gen,
|
|
EquipmentId = "eq-oven-3", EquipmentUuid = Guid.NewGuid(),
|
|
DriverInstanceId = DriverId, UnsLineId = "line-a", Name = "oven-3",
|
|
MachineCode = "MC-oven-3",
|
|
},
|
|
new Equipment
|
|
{
|
|
EquipmentRowId = Guid.NewGuid(), GenerationId = Gen,
|
|
EquipmentId = "eq-press-7", EquipmentUuid = Guid.NewGuid(),
|
|
DriverInstanceId = DriverId, UnsLineId = "line-a", Name = "press-7",
|
|
MachineCode = "MC-press-7",
|
|
});
|
|
_db.Tags.AddRange(
|
|
new Tag
|
|
{
|
|
TagRowId = Guid.NewGuid(), GenerationId = Gen, TagId = "tag-temp",
|
|
DriverInstanceId = DriverId, EquipmentId = "eq-oven-3",
|
|
Name = "Temperature", DataType = "Int32",
|
|
AccessLevel = TagAccessLevel.ReadWrite, TagConfig = "plcaddr-temperature",
|
|
},
|
|
new Tag
|
|
{
|
|
TagRowId = Guid.NewGuid(), GenerationId = Gen, TagId = "tag-press",
|
|
DriverInstanceId = DriverId, EquipmentId = "eq-press-7",
|
|
Name = "PressTemp", DataType = "Int32",
|
|
AccessLevel = TagAccessLevel.ReadWrite, TagConfig = "plcaddr-press-temp",
|
|
});
|
|
_db.SaveChanges();
|
|
}
|
|
}
|