using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common; namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.Tests; public sealed class QuestDbSchemaBootstrapperFailureTests { private sealed class ManualClock : TimeProvider { private DateTimeOffset _now = new(2026, 10, 11, 0, 0, 0, TimeSpan.Zero); public override DateTimeOffset GetUtcNow() => _now; public void Advance(TimeSpan by) => _now += by; } [Fact] public async Task A_failure_is_cached_for_five_seconds_then_retried() { var opts = new QuestDbHistorianOptions { ConnectionString = "Host=127.0.0.1;Port=1;Timeout=1" }; var clock = new ManualClock(); var boot = new QuestDbSchemaBootstrapper(new QuestDbConnection(opts), opts, timeProvider: clock); var first = await Should.ThrowAsync(() => boot.EnsureAsync(CancellationToken.None)); // Within the window the SAME failure is re-thrown without another connection attempt. var second = await Should.ThrowAsync(() => boot.EnsureAsync(CancellationToken.None)); second.ShouldBeSameAs(first); clock.Advance(BootstrapFailureCache.DefaultDuration + TimeSpan.FromSeconds(1)); var third = await Should.ThrowAsync(() => boot.EnsureAsync(CancellationToken.None)); third.ShouldNotBeSameAs(first); // the window closed: QuestDB was tried again } }