using Microsoft.Extensions.Logging.Abstractions; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Configuration.LocalCache; using ZB.MOM.WW.OtOpcUa.Server; namespace ZB.MOM.WW.OtOpcUa.Server.Tests; [Trait("Category", "Unit")] public sealed class NodeBootstrapTests { private sealed class StubCache : ILocalConfigCache { public GenerationSnapshot? Stored { get; set; } public Task GetMostRecentAsync(string _, CancellationToken __) => Task.FromResult(Stored); public Task PutAsync(GenerationSnapshot _, CancellationToken __) => Task.CompletedTask; public Task PruneOldGenerationsAsync(string _, int __, CancellationToken ___) => Task.CompletedTask; } [Fact] public async Task Falls_back_to_cache_when_DB_unreachable() { var cache = new StubCache { Stored = new GenerationSnapshot { ClusterId = "c", GenerationId = 42, CachedAt = DateTime.UtcNow, PayloadJson = "{}", }, }; var bootstrap = new NodeBootstrap( new NodeOptions { NodeId = "n", ClusterId = "c", ConfigDbConnectionString = "Server=127.0.0.1,59999;Database=nope;User Id=x;Password=x;TrustServerCertificate=True;Connect Timeout=1;", }, cache, NullLogger.Instance); var result = await bootstrap.LoadCurrentGenerationAsync(CancellationToken.None); result.Source.ShouldBe(BootstrapSource.LocalCache); result.GenerationId.ShouldBe(42); } [Fact] public async Task Throws_BootstrapException_when_DB_unreachable_and_cache_empty() { var bootstrap = new NodeBootstrap( new NodeOptions { NodeId = "n", ClusterId = "c", ConfigDbConnectionString = "Server=127.0.0.1,59999;Database=nope;User Id=x;Password=x;TrustServerCertificate=True;Connect Timeout=1;", }, new StubCache(), NullLogger.Instance); await Should.ThrowAsync(() => bootstrap.LoadCurrentGenerationAsync(CancellationToken.None)); } }