diff --git a/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs b/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs index 823c82f2..90fb7c94 100644 --- a/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs +++ b/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs @@ -198,6 +198,9 @@ public static class CultDocumentMessagePackSerialization if (fieldCount > 0) { + // A stamp encoded as binary is not one this runtime wrote or reads; it is refused here, not parsed as damage. + if (reader.NextMessagePackType == MessagePackType.Binary) + throw new NotSupportedException("Store snapshot declares its format version as binary; this runtime reads " + CultPersistedStoreSnapshot.FormatV1 + " and " + CultPersistedStoreSnapshot.FormatV2 + " as strings."); snapshot.FormatVersion = reader.ReadString() ?? throw new NotSupportedException("Store snapshot declares no format version; this runtime reads " + CultPersistedStoreSnapshot.FormatV1 + " and " + CultPersistedStoreSnapshot.FormatV2 + "."); requireReadable(snapshot.FormatVersion); diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 7e88c283..543261ff 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -428,7 +428,7 @@ namespace GameCult.Caching.Tests await seed.FlushAsync(); } - var manifest = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); + var manifest = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath), _ => { }); Assert.That(manifest.FormatVersion, Is.EqualTo("cultcache.store.v4.directory-content-addressed-pages")); Assert.That(manifest.Records, Has.Length.EqualTo(2)); Assert.That(manifest.Records.All(record => record.Payload.Length == 32), Is.True, @@ -730,7 +730,7 @@ namespace GameCult.Caching.Tests } Assert.That(store.IsDirty, Is.False); - var compacted = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath)); + var compacted = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(filePath), _ => { }); Assert.That(compacted.SchemaCatalog, Is.Empty); Assert.That(compacted.Records, Is.Empty); var reader = new CultCache(); diff --git a/tests/GameCult.Caching.Tests/DirectoryStoreDurabilityTests.cs b/tests/GameCult.Caching.Tests/DirectoryStoreDurabilityTests.cs index 840110bc..972648f5 100644 --- a/tests/GameCult.Caching.Tests/DirectoryStoreDurabilityTests.cs +++ b/tests/GameCult.Caching.Tests/DirectoryStoreDurabilityTests.cs @@ -223,7 +223,7 @@ namespace GameCult.Caching.Tests } private CultPersistedRecord ManifestRecord(CultRecordKey key) => - CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(_manifest)).Records.Single(record => record.Key == key.Value); + CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(_manifest), _ => { }).Records.Single(record => record.Key == key.Value); private string PagePath(byte[] identity) => Path.Combine(_records, BitConverter.ToString(identity).Replace("-", string.Empty).ToLowerInvariant() + ".msgpack"); diff --git a/tests/GameCult.Caching.Tests/PreCut2StoreFormatTests.cs b/tests/GameCult.Caching.Tests/PreCut2StoreFormatTests.cs index 7e339945..7f40f913 100644 --- a/tests/GameCult.Caching.Tests/PreCut2StoreFormatTests.cs +++ b/tests/GameCult.Caching.Tests/PreCut2StoreFormatTests.cs @@ -47,7 +47,7 @@ namespace GameCult.Caching.Tests try { var manifest = Path.Combine(root, "store.cc"); - Assert.That(CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(manifest)).FormatVersion, + Assert.That(CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(manifest), _ => { }).FormatVersion, Is.EqualTo("cultcache.store.v4.directory-content-addressed-pages")); using var cache = new CultCache(); @@ -342,16 +342,6 @@ namespace GameCult.Caching.Tests CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload, Registry); } - private sealed class FlakyReadStore : SingleFileMessagePackBackingStore - { - public Exception? FailReadWith; - - public FlakyReadStore(string path) : base(path) { } - - protected override CultPersistedStoreSnapshot DeserializeSnapshot(byte[] data) => - FailReadWith != null ? throw FailReadWith : base.DeserializeSnapshot(data); - } - private static void StampHeader(string file, string header) { var snapshot = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(file)); @@ -431,15 +421,16 @@ namespace GameCult.Caching.Tests try { var file = Path.Combine(root, "store.msgpack"); - var store = new FlakyReadStore(file); using var cache = new CultCache(); - cache.AddBackingStore(store); + cache.AddBackingStore(new SingleFileMessagePackBackingStore(file)); await cache.PullAllBackingStoresAsync(); var before = File.ReadAllBytes(file); await cache.AddAsync(new PreCut2FixtureNote { Text = "staged" }); - store.FailReadWith = new IOException("transient"); - Assert.Throws(() => cache.FlushAllBackingStores()); + using (new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) + { + Assert.Throws(() => cache.FlushAllBackingStores()); + } Assert.That(File.ReadAllBytes(file), Is.EqualTo(before)); } finally @@ -460,7 +451,7 @@ namespace GameCult.Caching.Tests cache.AddBackingStore(new DirectoryMessagePackBackingStore(manifest)); await cache.PullAllBackingStoresAsync(); - var snapshot = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(manifest)); + var snapshot = CultDocumentMessagePackSerialization.DeserializeSnapshot(File.ReadAllBytes(manifest), _ => { }); snapshot.FormatVersion = newer; File.WriteAllBytes(manifest, CultDocumentMessagePackSerialization.SerializeSnapshot(snapshot)); Func> files = () => Directory