using Microsoft.EntityFrameworkCore; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Configuration.Entities; using ZB.MOM.WW.OtOpcUa.Configuration.Enums; using ZB.MOM.WW.OtOpcUa.Configuration.Validation; namespace ZB.MOM.WW.OtOpcUa.Configuration.Tests; /// /// Verifies materialises a /// from the live config DB whose Tag/VirtualTag rows feed the /// equipment-signal collision rule — the one rule wired into the deploy gate (Task 3). /// [Trait("Category", "Unit")] public sealed class DraftSnapshotFactoryTests : IDisposable { private readonly OtOpcUaConfigDbContext _db; /// Initializes a new instance with an isolated in-memory config DB. public DraftSnapshotFactoryTests() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase($"draft-snapshot-{Guid.NewGuid():N}") .Options; _db = new OtOpcUaConfigDbContext(options); } /// Disposes the database context. public void Dispose() => _db.Dispose(); /// Seeds one Equipment plus a Tag and a VirtualTag sharing (EquipmentId, Name); the /// snapshot must carry both signal collections AND the validator must flag the collision. [Fact] public async Task FromConfigDb_populates_Tags_and_VirtualTags_and_surfaces_collision() { SeedEquipment("eq-1"); _db.Tags.Add(BuildTag(equipmentId: "eq-1", name: "speed")); _db.VirtualTags.Add(BuildVirtualTag(equipmentId: "eq-1", name: "speed")); await _db.SaveChangesAsync(); var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db); snapshot.Tags.Count.ShouldBe(1); snapshot.VirtualTags.Count.ShouldBe(1); DraftValidator.Validate(snapshot).ShouldContain(e => e.Code == "EquipmentSignalNameCollision"); } /// A Tag and a VirtualTag with distinct names under the same equipment do not collide, /// so the snapshot validates clean of the collision code. [Fact] public async Task FromConfigDb_no_collision_when_names_differ() { SeedEquipment("eq-1"); _db.Tags.Add(BuildTag(equipmentId: "eq-1", name: "speed")); _db.VirtualTags.Add(BuildVirtualTag(equipmentId: "eq-1", name: "temperature")); await _db.SaveChangesAsync(); var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db); snapshot.Tags.Count.ShouldBe(1); snapshot.VirtualTags.Count.ShouldBe(1); DraftValidator.Validate(snapshot).ShouldNotContain(e => e.Code == "EquipmentSignalNameCollision"); } private void SeedEquipment(string equipmentId) { var uuid = Guid.NewGuid(); _db.Equipment.Add(new Equipment { EquipmentUuid = uuid, EquipmentId = equipmentId, Name = "eq", DriverInstanceId = "d", UnsLineId = "line-a", MachineCode = "m", }); } private static Tag BuildTag(string equipmentId, string name) => new() { TagId = $"tag-{name}", DriverInstanceId = "d", EquipmentId = equipmentId, Name = name, DataType = "Float", AccessLevel = TagAccessLevel.Read, TagConfig = "{}", }; private static VirtualTag BuildVirtualTag(string equipmentId, string name) => new() { VirtualTagId = $"vtag-{name}", EquipmentId = equipmentId, Name = name, DataType = "Float", ScriptId = "s-1", }; }