feat(uns): validate typed TagConfig before save (F-uns-2 / #156)
v2-ci / build (push) Failing after 38s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped

The per-driver editor models expose Validate() (required-field checks) but the
TagModal never called them, so a blank required field (e.g. S7 address, AbCip
tag path) saved silently and only failed at deploy/connect. Add a
TagConfigValidator registry (DriverType -> model.FromJson(json).Validate(),
parallel to TagConfigEditorMap) and call it in SaveAsync before the service
call — a non-null result sets the modal error and blocks save. Unmapped drivers
(no typed editor) and Modbus (no required field) return null. Editors untouched.

AdminUI.Tests 307/307 (12 new validator tests); build clean.
This commit is contained in:
Joseph Doherty
2026-06-09 11:45:35 -04:00
parent d29e2190a9
commit fa96989e2a
3 changed files with 87 additions and 0 deletions
@@ -0,0 +1,49 @@
using Shouldly;
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
public sealed class TagConfigValidatorTests
{
[Fact]
public void No_driver_type_is_valid()
=> TagConfigValidator.Validate(null, "{}").ShouldBeNull();
[Fact]
public void Unmapped_driver_has_no_typed_validator_so_is_valid()
=> TagConfigValidator.Validate("OpcUaClient", "{}").ShouldBeNull();
[Fact]
public void Modbus_has_no_required_field_so_empty_config_is_valid()
=> TagConfigValidator.Validate("ModbusTcp", "{}").ShouldBeNull();
// Drivers whose Validate() requires a field: blank config must return an error string.
[Theory]
[InlineData("S7")]
[InlineData("AbCip")]
[InlineData("AbLegacy")]
[InlineData("TwinCat")]
[InlineData("Focas")]
public void Required_field_blank_is_rejected(string driverType)
{
TagConfigValidator.Validate(driverType, "{}").ShouldNotBeNullOrEmpty();
TagConfigValidator.Validate(driverType, null).ShouldNotBeNullOrEmpty();
}
[Fact]
public void S7_with_address_is_valid()
=> TagConfigValidator.Validate("S7", """{"address":"DB1.DBW0"}""").ShouldBeNull();
[Fact]
public void AbCip_with_tag_path_is_valid()
=> TagConfigValidator.Validate("AbCip", """{"tagPath":"Program:Main.Speed"}""").ShouldBeNull();
[Fact]
public void TwinCat_with_symbol_path_is_valid()
=> TagConfigValidator.Validate("TwinCat", """{"symbolPath":"MAIN.bStart"}""").ShouldBeNull();
[Fact]
public void Driver_type_lookup_is_case_insensitive()
=> TagConfigValidator.Validate("s7", "{}").ShouldNotBeNullOrEmpty();
}