11b703708c
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
33 lines
1.4 KiB
C#
33 lines
1.4 KiB
C#
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<Exception>(() => boot.EnsureAsync(CancellationToken.None));
|
|
// Within the window the SAME failure is re-thrown without another connection attempt.
|
|
var second = await Should.ThrowAsync<Exception>(() => boot.EnsureAsync(CancellationToken.None));
|
|
second.ShouldBeSameAs(first);
|
|
|
|
clock.Advance(BootstrapFailureCache.DefaultDuration + TimeSpan.FromSeconds(1));
|
|
var third = await Should.ThrowAsync<Exception>(() => boot.EnsureAsync(CancellationToken.None));
|
|
third.ShouldNotBeSameAs(first); // the window closed: QuestDB was tried again
|
|
}
|
|
}
|