Tests: fixtures that were read-only because their type read the record whole now lose a slot; restamp tests fixed
The ForeignRecordTests read-only fixtures (another runtime's deck, the moving deck) had the same shape as the deck, which the type now reads whole and owns; each gets a slot the deck lacks, so it is read only by dropping it. RestampOnWriteTests and the successful-churn gate test are corrected from the first run. Not run at this commit. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5036244778
commit
da951adce0
3 changed files with 36 additions and 15 deletions
|
|
@ -1446,21 +1446,24 @@ namespace GameCult.Caching.Tests
|
|||
[Test]
|
||||
public void OneStoreCallTakesAtMostThreeGatesUnderSuccessfulAttachChurnAndThreeIsReached()
|
||||
{
|
||||
var rounds = 0;
|
||||
var registry = CultDocumentRegistry.ForTypes(new[] { typeof(IdDeck) });
|
||||
new SingleFileMessagePackBackingStore(_path).WriteDocument(new CultRecordKey("a"), new IdDeck { Name = "a" }, registry: registry);
|
||||
var mostTakes = 0;
|
||||
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(60);
|
||||
for (var round = 0; mostTakes < 3 && DateTime.UtcNow < deadline; round++)
|
||||
{
|
||||
rounds++;
|
||||
var store = new RoleStore(_path);
|
||||
store.ReleaseAttach.Set();
|
||||
var cache = new CultCache(registry);
|
||||
using var barrier = new Barrier(2);
|
||||
var takes = 0;
|
||||
var spin = (round % 16) * 40;
|
||||
var spin = (round % 128) * 20;
|
||||
var caller = new Thread(() =>
|
||||
{
|
||||
barrier.SignalAndWait();
|
||||
Thread.SpinWait(spin);
|
||||
CacheBackingStore.GateTakes = 0;
|
||||
store.ReadStoreSnapshot();
|
||||
takes = CacheBackingStore.GateTakes;
|
||||
|
|
@ -1468,7 +1471,6 @@ namespace GameCult.Caching.Tests
|
|||
var attacher = new Thread(() =>
|
||||
{
|
||||
barrier.SignalAndWait();
|
||||
Thread.SpinWait(spin);
|
||||
cache.AddBackingStore(store);
|
||||
});
|
||||
caller.Start();
|
||||
|
|
@ -1480,7 +1482,7 @@ namespace GameCult.Caching.Tests
|
|||
mostTakes = Math.Max(mostTakes, takes);
|
||||
}
|
||||
|
||||
Assert.That(mostTakes, Is.EqualTo(3), "a call that raced a successful attach took the third gate");
|
||||
Assert.That(mostTakes, Is.EqualTo(3), $"a call that raced a successful attach took the third gate ({rounds} rounds)");
|
||||
}
|
||||
|
||||
// Under attaches that fail, Cache read under the store's gate is always null (an attach publishes and retracts it inside one
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ namespace GameCult.Caching.Tests
|
|||
private static readonly string WidgetId = Full.GetRequired(Widget).SchemaId;
|
||||
|
||||
// Another writer's deck (an older or newer build, another runtime) under an id the deck does not declare. It declares the
|
||||
// deck's own id compatible, so it may rewrite the deck's records; the deck still reads them through that listing, read-only.
|
||||
private static readonly Type MovingDeck = Emit("ForeignSuiteMovingDeck", "tests.foreign_deck", "tests.foreign_deck.v3", new[] { new Field("Name", typeof(string), 0, IsName: true) }, new[] { DeckOnly.GetRequired(Deck).SchemaId });
|
||||
// deck's own id compatible, so it may rewrite the deck's records; the deck still reads them through that listing, but only by
|
||||
// dropping the Note slot it lacks, so it does not own them and holds them read-only.
|
||||
private static readonly Type MovingDeck = Emit("ForeignSuiteMovingDeck", "tests.foreign_deck", "tests.foreign_deck.v3", new[] { new Field("Name", typeof(string), 0, IsName: true), new Field("Note", typeof(string), 1) }, new[] { DeckOnly.GetRequired(Deck).SchemaId });
|
||||
private static readonly CultDocumentRegistry Moving = CultDocumentRegistry.ForTypes(new[] { MovingDeck });
|
||||
private static readonly string MovingId = Moving.GetRequired(MovingDeck).SchemaId;
|
||||
|
||||
|
|
@ -587,8 +588,8 @@ namespace GameCult.Caching.Tests
|
|||
|
||||
private const string OtherRuntimeId = "other.runtime.deck";
|
||||
|
||||
// A deck another runtime wrote under its own id for the deck's schema. This build reads it through the catalog's schema name,
|
||||
// but does not own the id.
|
||||
// A deck another runtime wrote under its own id for the deck's schema, with a slot this build lacks. This build reads it
|
||||
// through the catalog's schema name, but only by dropping that slot, so it does not own the id.
|
||||
private string OtherRuntimeStore(string name, bool withVariant = false)
|
||||
{
|
||||
var path = PathOf(name);
|
||||
|
|
@ -604,6 +605,7 @@ namespace GameCult.Caching.Tests
|
|||
entry.SchemaId = OtherRuntimeId;
|
||||
entry.ContentHash = OtherRuntimeId;
|
||||
entry.CompatibleSchemaIds = new[] { OtherRuntimeId };
|
||||
entry.Members = entry.Members.Append(new CultSchemaMemberCatalogEntry { Slot = 99, MemberName = "Dropped", TypeName = "System.String" }).ToArray();
|
||||
foreach (var record in snapshot.Records)
|
||||
record.SchemaId = OtherRuntimeId;
|
||||
// An older entry that also lists the id, first in the catalog: the entry that owns the id is the one that publishes it.
|
||||
|
|
|
|||
|
|
@ -184,7 +184,8 @@ namespace GameCult.Caching.Tests
|
|||
public void ADeclaredLossyDriftRecordIsWritable(bool directory)
|
||||
{
|
||||
var path = SeedWide(directory);
|
||||
Assert.That(WideRegistry.GetRequired<NoteWide>().SchemaId, Is.EqualTo(WideId), "the declaration names the lossy record's id");
|
||||
var wideId = WideRegistry.GetRequired<NoteWide>().SchemaId;
|
||||
Assert.That(wideId, Is.EqualTo(WideId), "the declaration names the lossy record's id: " + wideId);
|
||||
|
||||
using (var cache = Open(path, directory, DeclaringRegistry))
|
||||
Assert.That(cache.Commit(batch => batch.Upsert(new NoteGrownDeclaring { Name = "note", Value = 2 }, new CultRecordHandle<NoteGrownDeclaring>(Note))), Is.True);
|
||||
|
|
@ -236,18 +237,34 @@ namespace GameCult.Caching.Tests
|
|||
public void ExpectAgreesWithRestamp(bool directory)
|
||||
{
|
||||
var path = SeedNarrow(directory);
|
||||
var third = new CultRecordKey("third");
|
||||
using var cache = Open(path, directory, GrownRegistry);
|
||||
using var second = Open(path, directory, GrownRegistry);
|
||||
var observed = cache.Get(Note)!;
|
||||
|
||||
Assert.That(cache.Commit(batch => batch.ExpectUnchanged()), Is.True, "an unchanged drift record satisfies ExpectUnchanged");
|
||||
Assert.That(cache.Commit(batch =>
|
||||
{
|
||||
batch.Expect(Note, observed);
|
||||
batch.Expect(Note, cache.Get(Note));
|
||||
batch.ExpectUnchanged();
|
||||
batch.Upsert(new NoteGrown { Name = "third" }, new CultRecordHandle<NoteGrown>(third));
|
||||
}), Is.True, "an unchanged drift record satisfies Expect and ExpectUnchanged");
|
||||
|
||||
using var second = Open(path, directory, GrownRegistry);
|
||||
Assert.That(cache.Commit(batch =>
|
||||
{
|
||||
batch.Expect(Note, cache.Get(Note));
|
||||
batch.Upsert(new NoteGrown { Name = "note", Value = 2 }, new CultRecordHandle<NoteGrown>(Note));
|
||||
}), Is.True, "a batch that Expects the drift record and upserts it commits and restamps");
|
||||
Assert.That(cache.Commit(batch => batch.ExpectUnchanged()), Is.True, "the writer's later ExpectUnchanged holds");
|
||||
Assert.That(second.Commit(batch => batch.ExpectUnchanged()), Is.False, "a cache loaded before the restamp sees the bytes change");
|
||||
}), Is.True, "a batch that Expects the drift record and upserts it commits");
|
||||
Assert.That(StoredIdOf(path, directory, GrownRegistry, Note), Is.EqualTo(GrownRegistry.GetRequired<NoteGrown>().SchemaId), "and restamps it");
|
||||
|
||||
Assert.That(cache.Commit(batch =>
|
||||
{
|
||||
batch.ExpectUnchanged();
|
||||
batch.Upsert(new NoteGrown { Name = "fourth" }, new CultRecordHandle<NoteGrown>(new CultRecordKey("fourth")));
|
||||
}), Is.True, "the writer's later ExpectUnchanged holds");
|
||||
Assert.That(second.Commit(batch =>
|
||||
{
|
||||
batch.Expect(Note, second.Get(Note));
|
||||
batch.Upsert(new NoteGrown { Name = "note", Value = 3 }, new CultRecordHandle<NoteGrown>(Note));
|
||||
}), Is.False, "a cache loaded before the restamp fails its Expect: the bytes changed");
|
||||
}
|
||||
|
||||
private static string VectorPath(string name)
|
||||
|
|
|
|||
Loading…
Reference in a new issue