diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs index 88db5322..6d1432ad 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs @@ -31,14 +31,13 @@ public static class DraftValidator ValidateSameClusterNamespaceBinding(draft, errors); ValidateReservationPreflight(draft, errors); ValidateEquipmentIdDerivation(draft, errors); - ValidateDriverNamespaceCompatibility(draft, errors); ValidateNoEquipmentSignalNameCollision(draft, errors); - ValidateAliasTagFullName(draft, errors); + ValidateGalaxyTagFullName(draft, errors); return errors; } - private static void ValidateAliasTagFullName(DraftSnapshot draft, List errors) + private static void ValidateGalaxyTagFullName(DraftSnapshot draft, List errors) { var typeByDriver = draft.DriverInstances .ToDictionary(d => d.DriverInstanceId, d => d.DriverType, StringComparer.Ordinal); @@ -48,8 +47,8 @@ public static class DraftValidator if (!typeByDriver.TryGetValue(t.DriverInstanceId, out var dtype) || dtype != "GalaxyMxGateway") continue; if (string.IsNullOrWhiteSpace(ExtractTagConfigFullName(t.TagConfig))) - errors.Add(new("AliasTagMissingReference", - $"Alias tag '{t.TagId}' on equipment '{t.EquipmentId}' is missing a Galaxy reference (TagConfig.FullName)", + errors.Add(new("GalaxyTagMissingReference", + $"Galaxy tag '{t.TagId}' on equipment '{t.EquipmentId}' is missing a Galaxy reference (TagConfig.FullName)", t.TagId)); } } @@ -222,28 +221,6 @@ public static class DraftValidator } } - private static void ValidateDriverNamespaceCompatibility(DraftSnapshot draft, List errors) - { - var nsById = draft.Namespaces.ToDictionary(n => n.NamespaceId); - - foreach (var di in draft.DriverInstances) - { - if (!nsById.TryGetValue(di.NamespaceId, out var ns)) continue; - - var compat = ns.Kind switch - { - NamespaceKind.SystemPlatform => di.DriverType == "GalaxyMxGateway", - NamespaceKind.Equipment => di.DriverType != "GalaxyMxGateway", - _ => true, - }; - - if (!compat) - errors.Add(new("DriverNamespaceKindMismatch", - $"DriverInstance '{di.DriverInstanceId}' ({di.DriverType}) is not allowed in {ns.Kind} namespace", - di.DriverInstanceId)); - } - } - /// /// Phase 6.3 Stream A.2 + task #148 part 2 — managed pre-publish guard for cluster /// topology vs. . The SQL diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs index 5452884b..ef2eeed4 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs @@ -123,24 +123,11 @@ public sealed class DraftValidatorTests } /// Verifies that the canonical Galaxy driver type (GalaxyMxGateway, per PR 7.2 — - /// it was "Galaxy" pre-PR-7.2) is allowed in a SystemPlatform namespace, i.e. produces no - /// kind-mismatch error. + /// it was "Galaxy" pre-PR-7.2) is now a standard Equipment-kind driver: binding it to an + /// Equipment namespace produces no kind-mismatch error (the SystemPlatform namespace split + /// is being retired — Galaxy under Equipment is valid). [Fact] - public void GalaxyMxGateway_driver_in_SystemPlatform_namespace_is_allowed() - { - var draft = new DraftSnapshot - { - GenerationId = 1, ClusterId = "c", - Namespaces = [new Namespace { NamespaceId = "ns-1", ClusterId = "c", NamespaceUri = "urn:x", Kind = NamespaceKind.SystemPlatform }], - DriverInstances = [new DriverInstance { DriverInstanceId = "d-1", ClusterId = "c", NamespaceId = "ns-1", Name = "drv", DriverType = "GalaxyMxGateway", DriverConfig = "{}" }], - }; - - DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "DriverNamespaceKindMismatch"); - } - - /// Verifies that the canonical Galaxy driver type cannot be placed in an Equipment namespace. - [Fact] - public void GalaxyMxGateway_driver_in_Equipment_namespace_is_rejected() + public void GalaxyMxGateway_driver_in_Equipment_namespace_is_allowed() { var draft = new DraftSnapshot { @@ -149,21 +136,7 @@ public sealed class DraftValidatorTests DriverInstances = [new DriverInstance { DriverInstanceId = "d-1", ClusterId = "c", NamespaceId = "ns-1", Name = "drv", DriverType = "GalaxyMxGateway", DriverConfig = "{}" }], }; - DraftValidator.Validate(draft).ShouldContain(e => e.Code == "DriverNamespaceKindMismatch"); - } - - /// Verifies that a non-Galaxy driver cannot be placed in a SystemPlatform namespace. - [Fact] - public void NonGalaxy_driver_in_SystemPlatform_namespace_is_rejected() - { - var draft = new DraftSnapshot - { - GenerationId = 1, ClusterId = "c", - Namespaces = [new Namespace { NamespaceId = "ns-1", ClusterId = "c", NamespaceUri = "urn:x", Kind = NamespaceKind.SystemPlatform }], - DriverInstances = [new DriverInstance { DriverInstanceId = "d-1", ClusterId = "c", NamespaceId = "ns-1", Name = "drv", DriverType = "ModbusTcp", DriverConfig = "{}" }], - }; - - DraftValidator.Validate(draft).ShouldContain(e => e.Code == "DriverNamespaceKindMismatch"); + DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "DriverNamespaceKindMismatch"); } /// Verifies that all validation errors are reported simultaneously. @@ -181,7 +154,6 @@ public sealed class DraftValidatorTests var errors = DraftValidator.Validate(draft); errors.ShouldContain(e => e.Code == "BadCrossClusterNamespaceBinding"); - errors.ShouldContain(e => e.Code == "DriverNamespaceKindMismatch"); errors.ShouldContain(e => e.Code == "EquipmentIdNotDerived"); errors.ShouldContain(e => e.Code == "UnsSegmentInvalid"); } @@ -432,54 +404,54 @@ public sealed class DraftValidatorTests }; // ------------------------------------------------------------------------------------ - // ValidateAliasTagFullName — Galaxy alias tags must carry TagConfig.FullName + // ValidateGalaxyTagFullName — Galaxy equipment tags must carry TagConfig.FullName // ------------------------------------------------------------------------------------ /// Verifies that an equipment-scoped Tag bound to a GalaxyMxGateway driver whose - /// TagConfig has no FullName (an alias with no Galaxy reference) is rejected — it would + /// TagConfig has no FullName (a Galaxy tag with no Galaxy reference) is rejected — it would /// subscribe to nothing. [Fact] - public void AliasTag_missing_FullName_is_rejected() + public void GalaxyTag_missing_FullName_is_rejected() { var draft = new DraftSnapshot { GenerationId = 1, ClusterId = "c", DriverInstances = [new DriverInstance { DriverInstanceId = "d-galaxy", ClusterId = "c", NamespaceId = "ns-1", Name = "Galaxy", DriverType = "GalaxyMxGateway", DriverConfig = "{}" }], - Tags = [BuildTag(equipmentId: "eq-1", name: "alias", folderPath: null, driverInstanceId: "d-galaxy", tagConfig: "{}")], + Tags = [BuildTag(equipmentId: "eq-1", name: "galaxytag", folderPath: null, driverInstanceId: "d-galaxy", tagConfig: "{}")], }; - DraftValidator.Validate(draft).ShouldContain(e => e.Code == "AliasTagMissingReference" && e.Context == "tag-alias"); + DraftValidator.Validate(draft).ShouldContain(e => e.Code == "GalaxyTagMissingReference" && e.Context == "tag-galaxytag"); } - /// Verifies that an equipment-scoped Galaxy alias tag carrying a TagConfig.FullName + /// Verifies that an equipment-scoped Galaxy tag carrying a TagConfig.FullName /// reference is accepted. [Fact] - public void AliasTag_with_FullName_is_accepted() + public void GalaxyTag_with_FullName_is_accepted() { var draft = new DraftSnapshot { GenerationId = 1, ClusterId = "c", DriverInstances = [new DriverInstance { DriverInstanceId = "d-galaxy", ClusterId = "c", NamespaceId = "ns-1", Name = "Galaxy", DriverType = "GalaxyMxGateway", DriverConfig = "{}" }], - Tags = [BuildTag(equipmentId: "eq-1", name: "alias", folderPath: null, driverInstanceId: "d-galaxy", tagConfig: "{\"FullName\":\"X.Y\"}")], + Tags = [BuildTag(equipmentId: "eq-1", name: "galaxytag", folderPath: null, driverInstanceId: "d-galaxy", tagConfig: "{\"FullName\":\"X.Y\"}")], }; - DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "AliasTagMissingReference"); + DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "GalaxyTagMissingReference"); } /// Verifies that an equipment-scoped Tag bound to a NON-Galaxy driver with an empty - /// TagConfig is NOT flagged as an alias missing its reference — only GalaxyMxGateway-bound - /// equipment tags are aliases. + /// TagConfig is NOT flagged as a Galaxy tag missing its reference — only GalaxyMxGateway-bound + /// equipment tags carry the Galaxy FullName requirement. [Fact] - public void AliasTag_check_skips_nonGalaxy_equipment_tag() + public void GalaxyTag_check_skips_nonGalaxy_equipment_tag() { var draft = new DraftSnapshot { GenerationId = 1, ClusterId = "c", DriverInstances = [new DriverInstance { DriverInstanceId = "d-modbus", ClusterId = "c", NamespaceId = "ns-1", Name = "Modbus", DriverType = "Modbus", DriverConfig = "{}" }], - Tags = [BuildTag(equipmentId: "eq-1", name: "alias", folderPath: null, driverInstanceId: "d-modbus", tagConfig: "{}")], + Tags = [BuildTag(equipmentId: "eq-1", name: "galaxytag", folderPath: null, driverInstanceId: "d-modbus", tagConfig: "{}")], }; - DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "AliasTagMissingReference"); + DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "GalaxyTagMissingReference"); } // ------------------------------------------------------------------------------------