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; /// /// lmxopcua#781 item 2: a Sql tag's write block is checked at deploy by the driver's own parser /// (SqlWriteBlockInvalid), and its mode against the instance's provider (SqlWriteModeUnsupported). /// Both always block. /// [Trait("Category", "Unit")] public sealed class DraftValidatorSqlWriteBlockTests { private static string Kv(string write) => """{"model":"KeyValue","table":"t","keyColumn":"k","keyValue":"a","valueColumn":"v","writable":true,"write":""" + write + "}"; private static DraftSnapshot Draft(string driverConfig, string tagConfig, string driverType = "Sql") => new() { GenerationId = 1, ClusterId = "c", DriverInstances = [new DriverInstance { DriverInstanceId = "di", ClusterId = "c", Name = "sql", DriverType = driverType, DriverConfig = driverConfig }], Devices = [new Device { DeviceId = "dev", DriverInstanceId = "di", Name = "d", DeviceConfig = "{}" }], Tags = [new Tag { TagId = "t1", DeviceId = "dev", Name = "t", DataType = "Float64", AccessLevel = TagAccessLevel.ReadWrite, TagConfig = tagConfig }], }; [Theory] [InlineData("""{"mode":"Merge"}""", "'write.mode'")] [InlineData("""{"mode":"Update","oops":1}""", "unknown key 'oops'")] [InlineData("""{"mode":"Procedure"}""", "needs 'write.procedure'")] [InlineData("""{"stampTimestamp":true}""", "no timestamp column")] public void A_malformed_write_block_is_a_blocking_deploy_error_with_the_parsers_reason(string write, string reason) => DraftValidator.Validate(Draft("{}", Kv(write))).ShouldContain(e => e.Code == SqlTagDeployChecks.WriteBlockInvalidCode && e.Context == "t1" && e.Message.Contains(reason)); [Theory] [InlineData("""{"mode":"Update"}""")] [InlineData("""{"mode":"Insert"}""")] [InlineData("""{"mode":"Upsert"}""")] [InlineData("""{"mode":"Procedure","procedure":"dbo.SetSp","keyParam":"key"}""")] public void Positive_control_valid_blocks_on_SqlServer_are_quiet(string write) => DraftValidator.Validate(Draft("""{"provider":"SqlServer"}""", Kv(write))) .ShouldNotContain(e => e.Code.StartsWith("SqlWrite", StringComparison.Ordinal)); [Theory] [InlineData("""{"mode":"Upsert"}""", true)] [InlineData("""{"mode":"Procedure","procedure":"p"}""", true)] [InlineData("""{"mode":"Insert"}""", false)] [InlineData("""{"mode":"Update"}""", false)] public void Odbc_serves_update_and_insert_only(string write, bool refused) => DraftValidator.Validate(Draft("""{"provider":"odbc"}""", Kv(write))) .Any(e => e.Code == SqlTagDeployChecks.WriteModeUnsupportedCode && e.Context == "t1") .ShouldBe(refused); [Fact] public void An_absent_provider_is_SqlServer_so_upsert_is_accepted() => DraftValidator.Validate(Draft("{}", Kv("""{"mode":"Upsert"}"""))) .ShouldNotContain(e => e.Code == SqlTagDeployChecks.WriteModeUnsupportedCode); [Fact] public void Tags_of_other_drivers_are_not_checked() => DraftValidator.Validate(Draft("{}", Kv("""{"mode":"Merge"}"""), driverType: "Modbus")) .ShouldNotContain(e => e.Code == SqlTagDeployChecks.WriteBlockInvalidCode); }