feat(batch14): complete group1 write path and wave1 tests

This commit is contained in:
Joseph Doherty
2026-02-28 15:10:46 -05:00
parent 7670488369
commit 4f0a7f40fc
7 changed files with 869 additions and 6 deletions

View File

@@ -203,6 +203,177 @@ public sealed partial class JetStreamFileStoreTests
[Fact] // T:592
public void FileStoreTrailingSkipMsgsFromStreamStateFile_ShouldSucceed() => RunWaveBScenario(nameof(FileStoreTrailingSkipMsgsFromStreamStateFile_ShouldSucceed));
[Fact] // T:549
public void FileStoreTruncateRemovedBlock_ShouldSucceed()
{
WithStore((fs, _) =>
{
fs.StoreMsg("foo", null, "1"u8.ToArray(), 0).Seq.ShouldBe(1UL);
fs.StoreMsg("foo", null, "2"u8.ToArray(), 0).Seq.ShouldBe(2UL);
fs.StoreMsg("foo", null, "3"u8.ToArray(), 0).Seq.ShouldBe(3UL);
var before = fs.State();
before.Msgs.ShouldBe(3UL);
before.FirstSeq.ShouldBe(1UL);
before.LastSeq.ShouldBe(3UL);
before.NumDeleted.ShouldBe(0);
fs.RemoveMsg(2).Removed.ShouldBeTrue();
var mid = fs.State();
mid.Msgs.ShouldBe(2UL);
mid.FirstSeq.ShouldBe(1UL);
mid.LastSeq.ShouldBe(3UL);
mid.NumDeleted.ShouldBe(1);
fs.Truncate(2);
var after = fs.State();
after.Msgs.ShouldBe(1UL);
after.FirstSeq.ShouldBe(1UL);
after.LastSeq.ShouldBe(2UL);
after.NumDeleted.ShouldBe(1);
});
}
[Fact] // T:551
public void FileStoreRemoveBlockWithStaleStreamState_ShouldSucceed()
{
var root = NewRoot();
Directory.CreateDirectory(root);
JetStreamFileStore? fs = null;
JetStreamFileStore? reopened = null;
try
{
fs = JetStreamFileStore.NewFileStore(new FileStoreConfig { StoreDir = root }, DefaultStreamConfig());
var blk1 = CreateBlock(root, 1, "blk1-data"u8.ToArray());
var blk2 = CreateBlock(root, 2, "blk2-data"u8.ToArray());
var blk3 = CreateBlock(root, 3, "blk3-data"u8.ToArray());
fs.RecoverMsgBlock(1).Index.ShouldBe(1u);
fs.RecoverMsgBlock(2).Index.ShouldBe(2u);
fs.RecoverMsgBlock(3).Index.ShouldBe(3u);
fs.Stop();
fs = null;
File.Delete(blk2);
reopened = JetStreamFileStore.NewFileStore(new FileStoreConfig { StoreDir = root }, DefaultStreamConfig());
reopened.RecoverMsgBlock(1).Index.ShouldBe(1u);
reopened.RecoverMsgBlock(3).Index.ShouldBe(3u);
Should.Throw<FileNotFoundException>(() => reopened.RecoverMsgBlock(2));
}
finally
{
reopened?.Stop();
fs?.Stop();
if (Directory.Exists(root))
Directory.Delete(root, recursive: true);
}
}
[Fact] // T:561
public void FileStoreTombstonesSelectNextFirstCleanup_ShouldSucceed()
{
WithStore((fs, _) =>
{
for (var i = 0; i < 100; i++)
fs.StoreMsg("foo", null, "x"u8.ToArray(), 0);
for (ulong seq = 2; seq <= 100; seq++)
fs.RemoveMsg(seq).Removed.ShouldBeTrue();
var before = fs.State();
before.Msgs.ShouldBe(1UL);
before.FirstSeq.ShouldBe(1UL);
before.LastSeq.ShouldBe(100UL);
fs.RemoveMsg(1).Removed.ShouldBeTrue();
var after = fs.State();
after.Msgs.ShouldBe(0UL);
after.FirstSeq.ShouldBe(101UL);
after.LastSeq.ShouldBe(100UL);
});
}
[Fact] // T:572
public void FileStoreEmptyBlockContainsPriorTombstones_ShouldSucceed()
{
WithStore((fs, _) =>
{
fs.StoreMsg("foo", null, "1"u8.ToArray(), 0).Seq.ShouldBe(1UL);
fs.StoreMsg("foo", null, "2"u8.ToArray(), 0).Seq.ShouldBe(2UL);
fs.StoreMsg("foo", null, "3"u8.ToArray(), 0).Seq.ShouldBe(3UL);
fs.RemoveMsg(2).Removed.ShouldBeTrue();
fs.RemoveMsg(3).Removed.ShouldBeTrue();
var mid = fs.State();
mid.Msgs.ShouldBe(1UL);
mid.FirstSeq.ShouldBe(1UL);
mid.LastSeq.ShouldBe(3UL);
mid.Deleted.ShouldContain(2UL);
mid.Deleted.ShouldContain(3UL);
fs.StoreMsg("foo", null, "4"u8.ToArray(), 0).Seq.ShouldBe(4UL);
fs.RemoveMsg(1).Removed.ShouldBeTrue();
var after = fs.State();
after.Msgs.ShouldBe(1UL);
after.FirstSeq.ShouldBe(4UL);
after.LastSeq.ShouldBe(4UL);
(after.Deleted ?? Array.Empty<ulong>()).ShouldBeEmpty();
});
}
[Fact] // T:586
public void FileStoreLoadNextMsgSkipAhead_ShouldSucceed()
{
WithStore((fs, _) =>
{
for (var i = 0; i < 10; i++)
{
var subj = i % 2 == 0 ? "a" : "c";
fs.StoreMsg(subj, null, "x"u8.ToArray(), 0);
}
fs.StoreMsg("b", null, "target"u8.ToArray(), 0).Seq.ShouldBe(11UL);
var (headSm, headSeq) = fs.LoadNextMsg("b", false, 0, null);
headSm.ShouldNotBeNull();
headSm!.Subject.ShouldBe("b");
headSeq.ShouldBe(11UL);
var (interiorSm, interiorSeq) = fs.LoadNextMsg("b", false, 3, null);
interiorSm.ShouldNotBeNull();
interiorSm!.Subject.ShouldBe("b");
interiorSeq.ShouldBe(11UL);
});
}
[Fact] // T:587
public void FileStoreLoadNextMsgMultiSkipAhead_ShouldSucceed()
{
WithStore((fs, _) =>
{
for (var i = 0; i < 10; i++)
{
var subj = i % 2 == 0 ? "a" : "c";
fs.StoreMsg(subj, null, "x"u8.ToArray(), 0);
}
fs.StoreMsg("b", null, "target"u8.ToArray(), 0).Seq.ShouldBe(11UL);
var (headSm, headSeq) = fs.LoadNextMsgMulti(new[] { "b", "d" }, 11, null);
headSm.ShouldNotBeNull();
headSm!.Subject.ShouldBe("b");
headSeq.ShouldBe(11UL);
var (interiorSm, interiorSeq) = fs.LoadNextMsgMulti(new[] { "b", "d" }, 3, null);
interiorSm.ShouldNotBeNull();
interiorSeq.ShouldBeGreaterThanOrEqualTo(3UL);
});
}
private static void RunWaveBScenario(string scenario)
{
switch (scenario)