using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
///
/// Gitea #516 — OpcUaClientDriver.InitializeAsync used to serve the options its CONSTRUCTOR
/// captured. Its own comment claimed "resolving on every InitializeAsync … picks up rotations", which
/// was true of SECRET rotation only: the endpoint, the security policy and the tag set were all frozen
/// at construction, so an operator's edit was discarded while the deployment still sealed green.
///
[Trait("Category", "Unit")]
public sealed class OpcUaClientReinitConfigAdoptionTests
{
///
/// ValidateNamespaceKind runs at the top of init and rejects TargetNamespaceKind=Equipment
/// with an empty UNS mapping table. Reinitializing INTO that shape must therefore throw — a driver
/// still serving the constructor's valid options would validate those and succeed, which is exactly
/// how the discarded edit stayed invisible.
///
[Fact]
public async Task Reinitialize_adopts_a_changed_config()
{
var driver = OpcUaClientDriverFactoryExtensions.CreateInstance(
"opc1",
"""{"endpointUrl":"opc.tcp://10.0.0.1:4840","targetNamespaceKind":"Equipment","unsMappingTable":{"a":"b"}}""");
await Should.ThrowAsync(
() => driver.ReinitializeAsync(
"""{"endpointUrl":"opc.tcp://10.0.0.1:4840","targetNamespaceKind":"Equipment","unsMappingTable":{}}""",
CancellationToken.None),
"OpcUaClientDriver kept its constructor-supplied options after a reinitialize with a changed config (#516)");
}
/// An empty/placeholder document must still keep the constructor options.
[Fact]
public async Task Reinitialize_with_an_empty_document_keeps_the_constructor_options()
{
var driver = OpcUaClientDriverFactoryExtensions.CreateInstance(
"opc1",
"""{"endpointUrl":"opc.tcp://10.0.0.1:4840","targetNamespaceKind":"Equipment","unsMappingTable":{"a":"b"}}""");
// "{}" keeps the (valid) constructor options, so ValidateNamespaceKind passes and the driver gets as
// far as the connect — which fails against an unreachable endpoint. Anything BUT the validation
// throw proves the constructor options survived.
var ex = await Record.ExceptionAsync(() => driver.ReinitializeAsync("{}", CancellationToken.None));
(ex is InvalidOperationException ioe && ioe.Message.Contains("UnsMappingTable", StringComparison.OrdinalIgnoreCase))
.ShouldBeFalse("an empty document must keep the constructor-supplied options, not re-validate an empty config");
}
}