CultCache mints storedAt from an internal Clock (default the wall clock); the vector writer pins it, so union-surface.cc is regenerated in process and byte-compared on every run. The gate test sets the switch itself and writes only a probe, so it neither skips nor touches a committed vector. This commit does not pass: union-surface.cc still holds the old wall-clock stored-at; the next commit regenerates it. Builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
2.6 KiB
C#
69 lines
2.6 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using GameCult.Caching;
|
|
using GameCult.Caching.MessagePack;
|
|
using NUnit.Framework;
|
|
|
|
namespace GameCult.Caching.Tests
|
|
{
|
|
// The clock behind every storedAt: the wall clock by default, and a pinned one when a golden store has to reproduce.
|
|
public class CultCacheClockTests
|
|
{
|
|
private static readonly CultDocumentRegistry Registry = CultDocumentRegistry.ForTypes(new[] { typeof(UnionParityVectorTests.UnionSurface) });
|
|
private static readonly CultRecordKey Key = new("surface");
|
|
|
|
private string _directory = string.Empty;
|
|
|
|
[SetUp]
|
|
public void CreateDirectory()
|
|
{
|
|
_directory = Path.Combine(Path.GetTempPath(), $"cultlib-clock-{Guid.NewGuid():N}");
|
|
Directory.CreateDirectory(_directory);
|
|
}
|
|
|
|
[TearDown]
|
|
public void DeleteDirectory()
|
|
{
|
|
if (Directory.Exists(_directory)) Directory.Delete(_directory, recursive: true);
|
|
}
|
|
|
|
private CultCache Open() => CultCacheMessagePack.Create(Path.Combine(_directory, "clock.cc"), new CultCacheOpenOptions { Registry = Registry });
|
|
|
|
private static string Upsert(CultCache cache)
|
|
{
|
|
cache.UpsertAsync(typeof(UnionParityVectorTests.UnionSurface), new UnionParityVectorTests.UnionSurface(), Key).GetAwaiter().GetResult();
|
|
return cache.GetStored(Key)!.StoredAt;
|
|
}
|
|
|
|
[Test]
|
|
public void ADefaultCacheStampsTheWallClock()
|
|
{
|
|
using var cache = Open();
|
|
var before = DateTimeOffset.UtcNow;
|
|
var stamp = DateTimeOffset.Parse(Upsert(cache), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
|
|
var after = DateTimeOffset.UtcNow;
|
|
Assert.That(stamp, Is.InRange(before, after));
|
|
}
|
|
|
|
[Test]
|
|
public void APinnedClockIsTheStoredAt()
|
|
{
|
|
var pinned = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
|
using var cache = Open();
|
|
cache.Clock = () => pinned;
|
|
Assert.That(Upsert(cache), Is.EqualTo("2026-01-01T00:00:00.0000000+00:00"));
|
|
}
|
|
|
|
[Test]
|
|
public void APinnedClockStillIncreasesStoredAtPerKey()
|
|
{
|
|
var pinned = new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
|
using var cache = Open();
|
|
cache.Clock = () => pinned;
|
|
Upsert(cache);
|
|
Assert.That(Upsert(cache), Is.EqualTo("2026-01-01T00:00:00.0000001+00:00"), "the same instant again is one tick later");
|
|
}
|
|
}
|
|
}
|