using Shouldly; using Xunit; namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests; /// /// Gitea #516 — AbLegacyDriver.InitializeAsync used to serve the options its CONSTRUCTOR /// captured and never look at the driverConfigJson it was handed, so an operator's config edit /// was silently discarded while the deployment still sealed green. /// Every pre-existing reinit test in this suite passes "{}" — the exact input the guarded /// re-parser treats as "keep the constructor options" — so they were blind to the defect. /// [Trait("Category", "Unit")] public sealed class AbLegacyReinitConfigAdoptionTests { /// /// The driver validates every device's HostAddress during init. Reinitializing with a config /// whose device address is structurally invalid must therefore THROW — a driver still serving the /// constructor's valid device list would validate that instead and succeed, which is precisely how /// the discarded edit stayed invisible. /// [Fact] public async Task Reinitialize_adopts_a_changed_device_list() { var driver = AbLegacyDriverFactoryExtensions.CreateInstance( "ab1", """{"devices":[{"hostAddress":"ab://10.0.0.1:44818/1,0","plcFamily":"Slc500"}]}""", loggerFactory: null); await Should.ThrowAsync( () => driver.ReinitializeAsync( """{"devices":[{"hostAddress":"not-a-valid-ab-address","plcFamily":"Slc500"}]}""", CancellationToken.None), "AbLegacyDriver kept its constructor-supplied device list after a reinitialize with a changed config (#516)"); } /// An empty/placeholder document must still keep the constructor options, so the many /// lifecycle tests that pass "{}" keep meaning what they meant. [Fact] public async Task Reinitialize_with_an_empty_document_keeps_the_constructor_options() { var driver = AbLegacyDriverFactoryExtensions.CreateInstance( "ab1", """{"devices":[{"hostAddress":"ab://10.0.0.1:44818/1,0","plcFamily":"Slc500"}]}""", loggerFactory: null); await Should.NotThrowAsync(() => driver.ReinitializeAsync("{}", CancellationToken.None)); } }