refactor: extract NATS.Server.JetStream.Tests project
Move 225 JetStream-related test files from NATS.Server.Tests into a dedicated NATS.Server.JetStream.Tests project. This includes root-level JetStream*.cs files, storage test files (FileStore, MemStore, StreamStoreContract), and the full JetStream/ subfolder tree (Api, Cluster, Consumers, MirrorSource, Snapshots, Storage, Streams). Updated all namespaces, added InternalsVisibleTo, registered in the solution file, and added the JETSTREAM_INTEGRATION_MATRIX define.
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
// Reference: golang/nats-server/server/filestore_test.go
|
||||
// Tests ported from: TestFileStorePurge, TestFileStoreCompact,
|
||||
// TestFileStoreCompactLastPlusOne, TestFileStoreCompactMsgCountBug,
|
||||
// TestFileStorePurgeExWithSubject, TestFileStorePurgeExKeepOneBug,
|
||||
// TestFileStorePurgeExNoTombsOnBlockRemoval,
|
||||
// TestFileStoreStreamTruncate
|
||||
|
||||
using System.Text;
|
||||
using NATS.Server.JetStream.Storage;
|
||||
|
||||
namespace NATS.Server.JetStream.Tests.JetStream.Storage;
|
||||
|
||||
public sealed class FileStorePurgeTests : IDisposable
|
||||
{
|
||||
private readonly string _dir;
|
||||
|
||||
public FileStorePurgeTests()
|
||||
{
|
||||
_dir = Path.Combine(Path.GetTempPath(), $"nats-js-fs-purge-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(_dir);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Directory.Exists(_dir))
|
||||
Directory.Delete(_dir, recursive: true);
|
||||
}
|
||||
|
||||
private FileStore CreateStore(string subdirectory, FileStoreOptions? options = null)
|
||||
{
|
||||
var dir = Path.Combine(_dir, subdirectory);
|
||||
var opts = options ?? new FileStoreOptions();
|
||||
opts.Directory = dir;
|
||||
return new FileStore(opts);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:709
|
||||
[Fact]
|
||||
public async Task Purge_removes_all_messages()
|
||||
{
|
||||
await using var store = CreateStore("purge-all");
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
await store.AppendAsync("foo", new byte[128], default);
|
||||
|
||||
(await store.GetStateAsync(default)).Messages.ShouldBe((ulong)100);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
|
||||
var state = await store.GetStateAsync(default);
|
||||
state.Messages.ShouldBe((ulong)0);
|
||||
state.Bytes.ShouldBe((ulong)0);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:740
|
||||
[Fact]
|
||||
public async Task Purge_recovers_same_state_after_restart()
|
||||
{
|
||||
var subDir = "purge-restart";
|
||||
|
||||
await using (var store = CreateStore(subDir))
|
||||
{
|
||||
for (var i = 0; i < 50; i++)
|
||||
await store.AppendAsync("foo", "Hello"u8.ToArray(), default);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
}
|
||||
|
||||
await using (var store = CreateStore(subDir))
|
||||
{
|
||||
var state = await store.GetStateAsync(default);
|
||||
state.Messages.ShouldBe((ulong)0);
|
||||
state.Bytes.ShouldBe((ulong)0);
|
||||
}
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:776
|
||||
[Fact]
|
||||
public async Task Store_after_purge_works()
|
||||
{
|
||||
await using var store = CreateStore("purge-then-store");
|
||||
|
||||
for (var i = 0; i < 20; i++)
|
||||
await store.AppendAsync("foo", "Hello"u8.ToArray(), default);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
|
||||
// New messages after purge.
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var seq = await store.AppendAsync("foo", "After purge"u8.ToArray(), default);
|
||||
seq.ShouldBeGreaterThan((ulong)0);
|
||||
}
|
||||
|
||||
var state = await store.GetStateAsync(default);
|
||||
state.Messages.ShouldBe((ulong)10);
|
||||
}
|
||||
|
||||
// Go: TestFileStoreCompact server/filestore_test.go:822
|
||||
[Fact(Skip = "Compact not yet implemented in .NET FileStore")]
|
||||
public async Task Compact_removes_messages_below_sequence()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStoreCompact server/filestore_test.go:851
|
||||
[Fact(Skip = "Compact not yet implemented in .NET FileStore")]
|
||||
public async Task Compact_beyond_last_seq_resets_first()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStoreCompact server/filestore_test.go:862
|
||||
[Fact(Skip = "Compact not yet implemented in .NET FileStore")]
|
||||
public async Task Compact_recovers_after_restart()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStoreCompactLastPlusOne server/filestore_test.go:875
|
||||
[Fact(Skip = "Compact not yet implemented in .NET FileStore")]
|
||||
public async Task Compact_last_plus_one_clears_all()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStoreCompactMsgCountBug server/filestore_test.go:916
|
||||
[Fact(Skip = "Compact not yet implemented in .NET FileStore")]
|
||||
public async Task Compact_with_prior_deletes_counts_correctly()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStoreStreamTruncate server/filestore_test.go:991
|
||||
[Fact(Skip = "Truncate not yet implemented in .NET FileStore")]
|
||||
public async Task Truncate_removes_messages_after_sequence()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStoreStreamTruncate server/filestore_test.go:1025
|
||||
[Fact(Skip = "Truncate not yet implemented in .NET FileStore")]
|
||||
public async Task Truncate_with_interior_deletes()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurgeExWithSubject server/filestore_test.go:3743
|
||||
[Fact(Skip = "PurgeEx not yet implemented in .NET FileStore")]
|
||||
public async Task PurgeEx_with_subject_removes_matching()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurgeExKeepOneBug server/filestore_test.go:3382
|
||||
[Fact(Skip = "PurgeEx not yet implemented in .NET FileStore")]
|
||||
public async Task PurgeEx_keep_one_preserves_last()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurgeExNoTombsOnBlockRemoval server/filestore_test.go:3823
|
||||
[Fact(Skip = "PurgeEx not yet implemented in .NET FileStore")]
|
||||
public async Task PurgeEx_no_tombstones_on_block_removal()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:709
|
||||
[Fact]
|
||||
public async Task Purge_then_list_returns_empty()
|
||||
{
|
||||
await using var store = CreateStore("purge-list");
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
await store.AppendAsync("foo", "data"u8.ToArray(), default);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
|
||||
var messages = await store.ListAsync(default);
|
||||
messages.Count.ShouldBe(0);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:709
|
||||
[Fact]
|
||||
public async Task Multiple_purges_are_safe()
|
||||
{
|
||||
await using var store = CreateStore("multi-purge");
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
await store.AppendAsync("foo", "data"u8.ToArray(), default);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
await store.PurgeAsync(default); // Double purge should not error.
|
||||
|
||||
(await store.GetStateAsync(default)).Messages.ShouldBe((ulong)0);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:709
|
||||
[Fact]
|
||||
public async Task Purge_empty_store_is_safe()
|
||||
{
|
||||
await using var store = CreateStore("purge-empty");
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
|
||||
(await store.GetStateAsync(default)).Messages.ShouldBe((ulong)0);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:709
|
||||
[Fact]
|
||||
public async Task Purge_with_prior_removes()
|
||||
{
|
||||
await using var store = CreateStore("purge-prior-rm");
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
await store.AppendAsync("foo", "data"u8.ToArray(), default);
|
||||
|
||||
// Remove some messages first.
|
||||
await store.RemoveAsync(2, default);
|
||||
await store.RemoveAsync(4, default);
|
||||
await store.RemoveAsync(6, default);
|
||||
|
||||
(await store.GetStateAsync(default)).Messages.ShouldBe((ulong)7);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
|
||||
var state = await store.GetStateAsync(default);
|
||||
state.Messages.ShouldBe((ulong)0);
|
||||
state.Bytes.ShouldBe((ulong)0);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:776
|
||||
[Fact]
|
||||
public async Task Purge_then_store_then_purge_again()
|
||||
{
|
||||
await using var store = CreateStore("purge-cycle");
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
await store.AppendAsync("foo", "data"u8.ToArray(), default);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
await store.AppendAsync("foo", "new data"u8.ToArray(), default);
|
||||
|
||||
(await store.GetStateAsync(default)).Messages.ShouldBe((ulong)3);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
(await store.GetStateAsync(default)).Messages.ShouldBe((ulong)0);
|
||||
}
|
||||
|
||||
// Go: TestFileStorePurge server/filestore_test.go:709
|
||||
[Fact]
|
||||
public async Task Purge_data_file_is_deleted()
|
||||
{
|
||||
var subDir = "purge-file";
|
||||
var dir = Path.Combine(_dir, subDir);
|
||||
|
||||
await using (var store = CreateStore(subDir))
|
||||
{
|
||||
for (var i = 0; i < 10; i++)
|
||||
await store.AppendAsync("foo", "data"u8.ToArray(), default);
|
||||
|
||||
await store.PurgeAsync(default);
|
||||
}
|
||||
|
||||
// The data file should be cleaned up or empty after purge.
|
||||
var dataFile = Path.Combine(dir, "messages.jsonl");
|
||||
if (File.Exists(dataFile))
|
||||
{
|
||||
var content = File.ReadAllText(dataFile);
|
||||
content.Trim().ShouldBeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user