Files
scadaproj/ZB.MOM.WW.LocalDb/tests/ZB.MOM.WW.LocalDb.Tests/HybridLogicalClockTests.cs
T

91 lines
2.6 KiB
C#

using ZB.MOM.WW.LocalDb.Hlc;
namespace ZB.MOM.WW.LocalDb.Tests;
public sealed class HybridLogicalClockTests
{
[Fact]
public void Next_IsStrictlyMonotonic()
{
var clock = new HybridLogicalClock();
var prev = clock.Next();
for (var i = 0; i < 1000; i++)
{
var next = clock.Next();
Assert.True(next > prev, $"call {i}: {next} !> {prev}");
prev = next;
}
}
[Fact]
public void Next_UsesUtcPhysicalMs()
{
const long fixedMs = 1_700_000_000_123;
var clock = new HybridLogicalClock(utcNowMs: () => fixedMs);
Assert.Equal(fixedMs, HybridLogicalClock.PhysicalMs(clock.Next()));
}
[Fact]
public void Next_SameMs_IncrementsCounter()
{
const long fixedMs = 1_700_000_000_000;
var clock = new HybridLogicalClock(utcNowMs: () => fixedMs);
var first = clock.Next();
var second = clock.Next();
var third = clock.Next();
Assert.Equal(0, HybridLogicalClock.Counter(first));
Assert.Equal(1, HybridLogicalClock.Counter(second));
Assert.Equal(2, HybridLogicalClock.Counter(third));
}
[Fact]
public void Observe_RemoteAhead_AdvancesPastRemote()
{
// Frozen wall clock well behind the remote stamp.
var clock = new HybridLogicalClock(utcNowMs: () => 1_000);
var remote = 5_000_000_000L << 16;
clock.Observe(remote);
Assert.True(clock.Next() > remote);
}
[Fact]
public void Observe_RemoteBehind_NoRegression()
{
var clock = new HybridLogicalClock(utcNowMs: () => 1_700_000_000_000);
var current = clock.Next();
clock.Observe(current - 1_000_000); // a stamp from the past
Assert.Equal(current, clock.Current);
}
[Fact]
public void Resume_FromPersistedValue_NeverRegresses()
{
// Persisted value is far ahead of what the (injected) wall clock yields.
var persisted = (2_000_000_000_000L << 16) | 0x00FF;
var clock = new HybridLogicalClock(initialValue: persisted, utcNowMs: () => 1_000);
Assert.True(clock.Next() > persisted);
}
[Fact]
public void CounterOverflow_RollsPhysicalForward()
{
const long ms = 1_700_000_000_000;
// Counter already maxed out under a frozen clock at the same physical ms.
var maxed = (ms << 16) | 0xFFFF;
var clock = new HybridLogicalClock(initialValue: maxed, utcNowMs: () => ms);
var next = clock.Next();
Assert.Equal(ms + 1, HybridLogicalClock.PhysicalMs(next));
Assert.Equal(0, HybridLogicalClock.Counter(next));
}
}