feat(batch13): port filestore all-last-seqs and filter-is-all helpers
This commit is contained in:
@@ -309,6 +309,141 @@ public sealed class JetStreamFileStoreReadQueryTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllLastSeqsLocked_MultipleSubjects_ReturnsSortedLastSequences()
|
||||
{
|
||||
var storeDir = CreateStoreDir();
|
||||
try
|
||||
{
|
||||
var fs = CreateStore(storeDir);
|
||||
SetField(fs, "_state", new StreamState { Msgs = 6UL });
|
||||
|
||||
var b1 = NewBlock(1, 1, 20);
|
||||
b1.Fss = BuildSubjectStateTree(("foo.a", 2, 10, 10), ("foo.b", 2, 20, 20));
|
||||
var b2 = NewBlock(2, 21, 40);
|
||||
b2.Fss = BuildSubjectStateTree(("foo.b", 1, 25, 25), ("foo.c", 1, 15, 15));
|
||||
|
||||
ConfigureBlocks(fs, b1, b2);
|
||||
SetPsims(fs, ("foo.a", 1, 1, 2), ("foo.b", 1, 2, 3), ("foo.c", 2, 2, 1));
|
||||
|
||||
var (seqs, error) = InvokeAllLastSeqsLocked(fs);
|
||||
|
||||
error.ShouldBeNull();
|
||||
seqs.ShouldBe([10UL, 15UL, 25UL]);
|
||||
fs.Stop();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteStoreDir(storeDir);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllLastSeqsLocked_NoMessagesOrNoTracking_ReturnsEmpty()
|
||||
{
|
||||
var storeDir = CreateStoreDir();
|
||||
try
|
||||
{
|
||||
var fs = CreateStore(storeDir);
|
||||
SetField(fs, "_state", new StreamState { Msgs = 0UL });
|
||||
SetPsims(fs, ("foo.a", 1, 1, 1));
|
||||
|
||||
var (noMsgsSeqs, noMsgsError) = InvokeAllLastSeqsLocked(fs);
|
||||
noMsgsError.ShouldBeNull();
|
||||
noMsgsSeqs.ShouldBeEmpty();
|
||||
fs.Stop();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteStoreDir(storeDir);
|
||||
}
|
||||
|
||||
var noTrackDir = CreateStoreDir();
|
||||
try
|
||||
{
|
||||
var fs = CreateStore(noTrackDir, subjects: []);
|
||||
SetField(fs, "_state", new StreamState { Msgs = 1UL });
|
||||
SetField(fs, "_psim", new SubjectTree<Psi>());
|
||||
|
||||
var (noTrackSeqs, noTrackError) = InvokeAllLastSeqsLocked(fs);
|
||||
noTrackError.ShouldBeNull();
|
||||
noTrackSeqs.ShouldBeEmpty();
|
||||
fs.Stop();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteStoreDir(noTrackDir);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllLastSeqsLocked_LastNeedsUpdate_RecalculatesBeforeCollecting()
|
||||
{
|
||||
var storeDir = CreateStoreDir();
|
||||
try
|
||||
{
|
||||
var fs = CreateStore(storeDir);
|
||||
SetField(fs, "_state", new StreamState { Msgs = 3UL });
|
||||
SetPsims(fs, ("foo.a", 1, 2, 3));
|
||||
|
||||
var b1 = NewBlock(1, 1, 12);
|
||||
b1.Fss = BuildSubjectStateTree(("foo.a", 3, 1, 12));
|
||||
|
||||
var b2 = NewBlock(2, 13, 20);
|
||||
var stale = new SimpleState { Msgs = 3UL, First = 1UL, Last = 0UL, LastNeedsUpdate = true };
|
||||
var staleTree = new SubjectTree<SimpleState>();
|
||||
staleTree.Insert(System.Text.Encoding.UTF8.GetBytes("foo.a"), stale);
|
||||
b2.Fss = staleTree;
|
||||
|
||||
ConfigureBlocks(fs, b1, b2);
|
||||
|
||||
var (seqs, error) = InvokeAllLastSeqsLocked(fs);
|
||||
|
||||
error.ShouldBeNull();
|
||||
seqs.ShouldBe([12UL]);
|
||||
fs.Stop();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteStoreDir(storeDir);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilterIsAll_ReorderedEquivalentFilters_ReturnsTrue()
|
||||
{
|
||||
var storeDir = CreateStoreDir();
|
||||
try
|
||||
{
|
||||
var fs = CreateStore(storeDir, ["foo.*", "bar.>"]);
|
||||
|
||||
InvokeFilterIsAll(fs, ["bar.>", "foo.*"]).ShouldBeTrue();
|
||||
fs.Stop();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteStoreDir(storeDir);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilterIsAll_CountMismatchOrNonSubset_ReturnsFalse()
|
||||
{
|
||||
var storeDir = CreateStoreDir();
|
||||
try
|
||||
{
|
||||
var fs = CreateStore(storeDir, ["foo.*", "bar.>"]);
|
||||
|
||||
InvokeFilterIsAll(fs, ["foo.A"]).ShouldBeFalse();
|
||||
InvokeFilterIsAll(fs, ["bar.>", "baz.*"]).ShouldBeFalse();
|
||||
fs.Stop();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteStoreDir(storeDir);
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateStoreDir()
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), $"fs-read-query-{Guid.NewGuid():N}");
|
||||
@@ -322,8 +457,10 @@ public sealed class JetStreamFileStoreReadQueryTests
|
||||
Directory.Delete(storeDir, recursive: true);
|
||||
}
|
||||
|
||||
private static JetStreamFileStore CreateStore(string storeDir)
|
||||
private static JetStreamFileStore CreateStore(string storeDir, string[]? subjects = null)
|
||||
{
|
||||
subjects ??= ["foo.*", "bar.*", "zoo.*"];
|
||||
|
||||
return new JetStreamFileStore(
|
||||
new FileStoreConfig { StoreDir = storeDir, BlockSize = 1024 },
|
||||
new FileStreamInfo
|
||||
@@ -333,7 +470,7 @@ public sealed class JetStreamFileStoreReadQueryTests
|
||||
{
|
||||
Name = "S",
|
||||
Storage = StorageType.FileStorage,
|
||||
Subjects = ["foo.*", "bar.*", "zoo.*"],
|
||||
Subjects = subjects,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -434,6 +571,24 @@ public sealed class JetStreamFileStoreReadQueryTests
|
||||
_ = mi!.Invoke(fs, [filter, ss]);
|
||||
}
|
||||
|
||||
private static (ulong[] Seqs, Exception? Error) InvokeAllLastSeqsLocked(JetStreamFileStore fs)
|
||||
{
|
||||
var mi = typeof(JetStreamFileStore).GetMethod("AllLastSeqsLocked", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
mi.ShouldNotBeNull();
|
||||
var result = mi!.Invoke(fs, []);
|
||||
result.ShouldNotBeNull();
|
||||
return ((ulong[], Exception?))result!;
|
||||
}
|
||||
|
||||
private static bool InvokeFilterIsAll(JetStreamFileStore fs, string[] filters)
|
||||
{
|
||||
var mi = typeof(JetStreamFileStore).GetMethod("FilterIsAll", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
mi.ShouldNotBeNull();
|
||||
var result = mi!.Invoke(fs, [filters]);
|
||||
result.ShouldNotBeNull();
|
||||
return (bool)result;
|
||||
}
|
||||
|
||||
private static Psi? GetPsi(JetStreamFileStore fs, string subject)
|
||||
{
|
||||
var fi = typeof(JetStreamFileStore).GetField("_psim", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
Reference in New Issue
Block a user