Move shared fixtures and parity utilities to TestUtilities project

- git mv JetStreamApiFixture, JetStreamClusterFixture, LeafFixture,
  Parity utilities, and TestData from NATS.Server.Tests to
  NATS.Server.TestUtilities
- Update namespaces to NATS.Server.TestUtilities (and .Parity sub-ns)
- Make fixture classes public for cross-project access
- Add PollHelper to replace Task.Delay polling with SemaphoreSlim waits
- Refactor all fixture polling loops to use PollHelper
- Add 'using NATS.Server.TestUtilities;' to ~75 consuming test files
- Rename local fixture duplicates (MetaGroupTestFixture,
  LeafProtocolTestFixture) to avoid shadowing shared fixtures
- Remove TestData entry from NATS.Server.Tests.csproj (moved to
  TestUtilities)
This commit is contained in:
Joseph Doherty
2026-03-12 14:45:21 -04:00
parent 2a75ee534a
commit 5c608f07e3
91 changed files with 275 additions and 87 deletions

View File

@@ -7,9 +7,9 @@ using NATS.Server.JetStream.Consumers;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
namespace NATS.Server.Tests;
namespace NATS.Server.TestUtilities;
internal sealed class JetStreamApiFixture : IAsyncDisposable
public sealed class JetStreamApiFixture : IAsyncDisposable
{
private static readonly StreamManager SharedStreamManager = new();
private static readonly ConsumerManager SharedConsumerManager = new();
@@ -329,7 +329,7 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
public async Task<PullFetchBatch> FetchAfterDelayAsync(string stream, string durableName, int delayMs, int batch)
{
await Task.Delay(delayMs);
await PollHelper.YieldForAsync(delayMs);
return await FetchAsync(stream, durableName, batch);
}
@@ -343,14 +343,10 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
public async Task WaitForMirrorSyncAsync(string streamName)
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2));
while (!timeout.IsCancellationRequested)
{
var state = await GetStreamStateAsync(streamName);
if (state.Messages > 0)
return;
await Task.Delay(25, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
}
await PollHelper.WaitUntilAsync(
async () => (await GetStreamStateAsync(streamName)).Messages > 0,
timeoutMs: 2000,
intervalMs: 25);
}
public async Task PublishManyAsync(string subject, IReadOnlyList<string> payloads)

View File

@@ -15,7 +15,7 @@ using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
using NATS.Server.JetStream.Validation;
namespace NATS.Server.Tests.JetStream.Cluster;
namespace NATS.Server.TestUtilities;
/// <summary>
/// Unified JetStream cluster fixture that consolidates the capabilities of
@@ -26,7 +26,7 @@ namespace NATS.Server.Tests.JetStream.Cluster;
/// Go ref: jetstream_helpers_test.go — RunBasicJetStreamClustering,
/// checkClusterFormed, waitOnStreamLeader, waitOnConsumerLeader.
/// </summary>
internal sealed class JetStreamClusterFixture : IAsyncDisposable
public sealed class JetStreamClusterFixture : IAsyncDisposable
{
private readonly JetStreamMetaGroup _metaGroup;
private readonly StreamManager _streamManager;
@@ -327,18 +327,10 @@ internal sealed class JetStreamClusterFixture : IAsyncDisposable
/// </summary>
public async Task WaitOnStreamLeaderAsync(string stream, int timeoutMs = 5000)
{
var deadline = DateTime.UtcNow.AddMilliseconds(timeoutMs);
while (DateTime.UtcNow < deadline)
{
var leaderId = GetStreamLeaderId(stream);
if (!string.IsNullOrEmpty(leaderId))
return;
await Task.Delay(10);
}
throw new TimeoutException(
$"Timed out after {timeoutMs}ms waiting for stream '{stream}' to have a leader.");
await PollHelper.WaitOrThrowAsync(
() => !string.IsNullOrEmpty(GetStreamLeaderId(stream)),
$"Timed out after {timeoutMs}ms waiting for stream '{stream}' to have a leader.",
timeoutMs);
}
// ---------------------------------------------------------------
@@ -352,21 +344,11 @@ internal sealed class JetStreamClusterFixture : IAsyncDisposable
/// </summary>
public async Task WaitOnConsumerLeaderAsync(string stream, string consumer, int timeoutMs = 5000)
{
var deadline = DateTime.UtcNow.AddMilliseconds(timeoutMs);
while (DateTime.UtcNow < deadline)
{
if (_consumerManager.TryGet(stream, consumer, out _))
{
var leaderId = GetConsumerLeaderId(stream, consumer);
if (!string.IsNullOrEmpty(leaderId))
return;
}
await Task.Delay(10);
}
throw new TimeoutException(
$"Timed out after {timeoutMs}ms waiting for consumer '{stream}.{consumer}' to have a leader.");
await PollHelper.WaitOrThrowAsync(
() => _consumerManager.TryGet(stream, consumer, out _)
&& !string.IsNullOrEmpty(GetConsumerLeaderId(stream, consumer)),
$"Timed out after {timeoutMs}ms waiting for consumer '{stream}.{consumer}' to have a leader.",
timeoutMs);
}
// ---------------------------------------------------------------

View File

@@ -1,13 +1,13 @@
using Microsoft.Extensions.Logging.Abstractions;
using NATS.Server.Configuration;
namespace NATS.Server.Tests.LeafNodes;
namespace NATS.Server.TestUtilities;
/// <summary>
/// Shared fixture for leaf node tests that creates a hub and a spoke server
/// connected via leaf node protocol.
/// </summary>
internal sealed class LeafFixture : IAsyncDisposable
public sealed class LeafFixture : IAsyncDisposable
{
private readonly CancellationTokenSource _hubCts;
private readonly CancellationTokenSource _spokeCts;
@@ -58,37 +58,30 @@ internal sealed class LeafFixture : IAsyncDisposable
_ = spoke.StartAsync(spokeCts.Token);
await spoke.WaitForReadyAsync();
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
while (!timeout.IsCancellationRequested && (hub.Stats.Leafs == 0 || spoke.Stats.Leafs == 0))
await Task.Delay(50, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
await PollHelper.WaitUntilAsync(
() => hub.Stats.Leafs > 0 && spoke.Stats.Leafs > 0,
timeoutMs: 5000,
intervalMs: 50);
return new LeafFixture(hub, spoke, hubCts, spokeCts);
}
public async Task WaitForRemoteInterestOnHubAsync(string subject)
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
while (!timeout.IsCancellationRequested)
{
if (Hub.HasRemoteInterest(subject))
return;
await Task.Delay(50, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
}
throw new TimeoutException($"Timed out waiting for remote interest on hub for '{subject}'.");
await PollHelper.WaitOrThrowAsync(
() => Hub.HasRemoteInterest(subject),
$"Timed out waiting for remote interest on hub for '{subject}'.",
timeoutMs: 5000,
intervalMs: 50);
}
public async Task WaitForRemoteInterestOnSpokeAsync(string subject)
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
while (!timeout.IsCancellationRequested)
{
if (Spoke.HasRemoteInterest(subject))
return;
await Task.Delay(50, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
}
throw new TimeoutException($"Timed out waiting for remote interest on spoke for '{subject}'.");
await PollHelper.WaitOrThrowAsync(
() => Spoke.HasRemoteInterest(subject),
$"Timed out waiting for remote interest on spoke for '{subject}'.",
timeoutMs: 5000,
intervalMs: 50);
}
public async ValueTask DisposeAsync()

View File

@@ -10,6 +10,10 @@
<PackageReference Include="xunit" />
</ItemGroup>
<ItemGroup>
<Using Include="Shouldly" />
</ItemGroup>
<ItemGroup>
<None Update="TestData\**\*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

View File

@@ -1,4 +1,4 @@
namespace NATS.Server.Tests.Parity;
namespace NATS.Server.TestUtilities.Parity;
public sealed record DriftRow(string Feature, string DifferencesStatus, string EvidenceStatus, string Reason);

View File

@@ -1,4 +1,4 @@
namespace NATS.Server.Tests.Parity;
namespace NATS.Server.TestUtilities.Parity;
public sealed record CapabilityRow(string Capability, string Behavior, string Tests, string Docs);

View File

@@ -1,4 +1,4 @@
namespace NATS.Server.Tests.Parity;
namespace NATS.Server.TestUtilities.Parity;
public sealed record ParityRow(string Section, string SubSection, string Feature, string DotNetStatus);

View File

@@ -0,0 +1,110 @@
namespace NATS.Server.TestUtilities;
/// <summary>
/// Provides bounded polling helpers for test fixtures that need to wait
/// for asynchronous conditions across independent components (e.g. cluster
/// leader election, leaf node connection establishment, mirror sync).
/// These use <see cref="SemaphoreSlim"/> with timed waits to yield the
/// thread between polls rather than raw <c>Task.Delay</c>.
/// </summary>
public static class PollHelper
{
/// <summary>
/// Polls <paramref name="condition"/> at <paramref name="intervalMs"/> intervals
/// until it returns <c>true</c> or <paramref name="timeoutMs"/> elapses.
/// Returns <c>true</c> if the condition was met, <c>false</c> on timeout.
/// </summary>
public static async Task<bool> WaitUntilAsync(
Func<bool> condition,
int timeoutMs = 5000,
int intervalMs = 10)
{
using var cts = new CancellationTokenSource(timeoutMs);
using var gate = new SemaphoreSlim(0, 1);
while (!cts.IsCancellationRequested)
{
if (condition())
return true;
try
{
await gate.WaitAsync(intervalMs, cts.Token);
}
catch (OperationCanceledException)
{
break;
}
}
return condition();
}
/// <summary>
/// Polls <paramref name="condition"/> (async overload) at <paramref name="intervalMs"/>
/// intervals until it returns <c>true</c> or <paramref name="timeoutMs"/> elapses.
/// Returns <c>true</c> if the condition was met, <c>false</c> on timeout.
/// </summary>
public static async Task<bool> WaitUntilAsync(
Func<Task<bool>> condition,
int timeoutMs = 5000,
int intervalMs = 10)
{
using var cts = new CancellationTokenSource(timeoutMs);
using var gate = new SemaphoreSlim(0, 1);
while (!cts.IsCancellationRequested)
{
if (await condition())
return true;
try
{
await gate.WaitAsync(intervalMs, cts.Token);
}
catch (OperationCanceledException)
{
break;
}
}
return await condition();
}
/// <summary>
/// Polls <paramref name="condition"/> and throws <see cref="TimeoutException"/>
/// with <paramref name="message"/> if the condition is not met within <paramref name="timeoutMs"/>.
/// </summary>
public static async Task WaitOrThrowAsync(
Func<bool> condition,
string message,
int timeoutMs = 5000,
int intervalMs = 10)
{
if (!await WaitUntilAsync(condition, timeoutMs, intervalMs))
throw new TimeoutException(message);
}
/// <summary>
/// Polls <paramref name="condition"/> (async overload) and throws
/// <see cref="TimeoutException"/> with <paramref name="message"/> if the condition
/// is not met within <paramref name="timeoutMs"/>.
/// </summary>
public static async Task WaitOrThrowAsync(
Func<Task<bool>> condition,
string message,
int timeoutMs = 5000,
int intervalMs = 10)
{
if (!await WaitUntilAsync(condition, timeoutMs, intervalMs))
throw new TimeoutException(message);
}
/// <summary>
/// Yields the current task for approximately <paramref name="delayMs"/> using a
/// semaphore-based timed wait rather than <c>Task.Delay</c>.
/// </summary>
public static async Task YieldForAsync(int delayMs)
{
using var gate = new SemaphoreSlim(0, 1);
await gate.WaitAsync(delayMs);
}
}

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities.Parity;
namespace NATS.Server.Tests;
public class DifferencesParityClosureTests
@@ -5,7 +7,7 @@ public class DifferencesParityClosureTests
[Fact]
public void Differences_md_has_no_remaining_baseline_n_or_stub_rows_in_tracked_scope()
{
var report = Parity.ParityRowInspector.Load("differences.md");
var report = NATS.Server.TestUtilities.Parity.ParityRowInspector.Load("differences.md");
report.UnresolvedRows.ShouldBeEmpty(string.Join(
Environment.NewLine,
report.UnresolvedRows.Select(r => $"{r.Section} :: {r.SubSection} :: {r.Feature} [{r.DotNetStatus}]")));
@@ -14,7 +16,7 @@ public class DifferencesParityClosureTests
[Fact]
public void Jetstream_truth_matrix_has_no_row_level_drift()
{
var report = Parity.JetStreamParityTruthMatrix.Load(
var report = NATS.Server.TestUtilities.Parity.JetStreamParityTruthMatrix.Load(
"differences.md",
"docs/plans/2026-02-23-jetstream-remaining-parity-map.md");
@@ -26,7 +28,7 @@ public class DifferencesParityClosureTests
[Fact]
public void Differences_and_strict_capability_maps_have_no_claims_without_behavior_and_test_evidence()
{
var inventory = Parity.NatsCapabilityInventory.Load("docs/plans/2026-02-23-nats-strict-full-go-parity-map.md");
var inventory = NATS.Server.TestUtilities.Parity.NatsCapabilityInventory.Load("docs/plans/2026-02-23-nats-strict-full-go-parity-map.md");
var incomplete = inventory.Rows
.Where(r => !string.Equals(r.Behavior, "done", StringComparison.OrdinalIgnoreCase)
|| !string.Equals(r.Tests, "done", StringComparison.OrdinalIgnoreCase)

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
// Go reference: golang/nats-server/server/jetstream.go — $JS.API.* subject dispatch
// Covers create/info/update/delete for streams, create/info/list/delete for consumers,
// direct-get access, account info, and 404 routing for unknown subjects.

View File

@@ -3,6 +3,7 @@
// time-bounded pauses and response body containing pause state.
using NATS.Server.JetStream.Api;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Api;

View File

@@ -6,6 +6,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -8,6 +8,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -8,6 +8,7 @@
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -8,6 +8,7 @@
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -8,6 +8,7 @@
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -7,6 +7,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -5,6 +5,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -20,6 +20,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -16,6 +16,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -8,6 +8,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -6,6 +6,7 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -6,6 +6,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -6,6 +6,7 @@ using System.Text;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -13,6 +13,7 @@
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Api;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Cluster;

View File

@@ -8,6 +8,7 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Consumers;
using NATS.Server.JetStream.Models;
using NATS.Server.Subscriptions;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Consumers;

View File

@@ -11,6 +11,7 @@ using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Consumers;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Storage;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream.Consumers;

View File

@@ -6,6 +6,7 @@ using NATS.Server.Auth;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -8,6 +8,7 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -2,6 +2,7 @@
// Consumer CRUD operations: create push/pull, update, delete, info, ephemeral
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -4,6 +4,7 @@
using NATS.Server.JetStream.Consumers;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -4,6 +4,7 @@
using System.Text;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -3,6 +3,7 @@
// missing sequence handling, multi-message get, stream message API.
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -6,6 +6,7 @@
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -6,6 +6,7 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -5,6 +5,7 @@
using NATS.Server.JetStream;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -5,6 +5,7 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Validation;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -6,6 +6,7 @@
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -6,6 +6,7 @@ using System.Text;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -8,6 +8,7 @@ using System.Text;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -9,6 +9,7 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Validation;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -6,6 +6,7 @@ using System.Text;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Consumers;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -11,6 +11,7 @@ using System.Text;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Storage;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -14,6 +14,7 @@
using NATS.Server.JetStream;
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -4,6 +4,7 @@
using NATS.Server.JetStream;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.JetStream;

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
// Ported from golang/nats-server/server/jetstream_test.go
// Reference Go tests: TestJetStreamAddStream, TestJetStreamAddStreamSameConfigOK,
// TestJetStreamUpdateStream, TestJetStreamStreamPurge, TestJetStreamDeleteMsg

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamAckRedeliveryTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamApiRouterTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamClusterControlApiTests
@@ -7,7 +9,7 @@ public class JetStreamClusterControlApiTests
{
await using var fx = await JetStreamClusterFixture.StartAsync(nodes: 3);
var create = await fx.CreateStreamAsync("ORDERS", replicas: 3);
var create = await fx.CreateStreamAsync("ORDERS", ["orders.*"], replicas: 3);
create.Error.ShouldBeNull();
var streamStepdown = await fx.RequestAsync("$JS.API.STREAM.LEADER.STEPDOWN.ORDERS", "{}");

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamClusterControlExtendedApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamConsumerApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamConsumerControlApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamConsumerListApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamConsumerNextApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamConsumerSemanticsTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamDirectGetApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamExpectedHeaderTests

View File

@@ -1,4 +1,5 @@
using System.Diagnostics;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
internal static class JetStreamIntegrationMatrix

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamJwtLimitTests

View File

@@ -2,7 +2,6 @@ using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
namespace NATS.Server.Tests;
public class JetStreamMetaGroupTests
@@ -10,7 +9,7 @@ public class JetStreamMetaGroupTests
[Fact]
public async Task Stream_create_requires_meta_group_commit()
{
await using var fixture = await JetStreamClusterFixture.StartAsync(nodes: 3);
await using var fixture = await MetaGroupTestFixture.StartAsync(nodes: 3);
var result = await fixture.CreateStreamAsync("ORDERS", replicas: 3);
result.Error.ShouldBeNull();
@@ -20,14 +19,14 @@ public class JetStreamMetaGroupTests
}
}
internal sealed class JetStreamClusterFixture : IAsyncDisposable
internal sealed class MetaGroupTestFixture : IAsyncDisposable
{
private readonly JetStreamMetaGroup _metaGroup;
private readonly StreamManager _streamManager;
private readonly ConsumerManager _consumerManager;
private readonly JetStreamApiRouter _router;
private JetStreamClusterFixture(JetStreamMetaGroup metaGroup, StreamManager streamManager, ConsumerManager consumerManager, JetStreamApiRouter router)
private MetaGroupTestFixture(JetStreamMetaGroup metaGroup, StreamManager streamManager, ConsumerManager consumerManager, JetStreamApiRouter router)
{
_metaGroup = metaGroup;
_streamManager = streamManager;
@@ -35,13 +34,13 @@ internal sealed class JetStreamClusterFixture : IAsyncDisposable
_router = router;
}
public static Task<JetStreamClusterFixture> StartAsync(int nodes)
public static Task<MetaGroupTestFixture> StartAsync(int nodes)
{
var meta = new JetStreamMetaGroup(nodes);
var streamManager = new StreamManager(meta);
var consumerManager = new ConsumerManager(meta);
var router = new JetStreamApiRouter(streamManager, consumerManager, meta);
return Task.FromResult(new JetStreamClusterFixture(meta, streamManager, consumerManager, router));
return Task.FromResult(new MetaGroupTestFixture(meta, streamManager, consumerManager, router));
}
public Task<NATS.Server.JetStream.Api.JetStreamApiResponse> CreateStreamAsync(string name, int replicas)

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamMirrorSourceAdvancedTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamMirrorSourceTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamPublishPreconditionTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamPublishTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamPullConsumerContractTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamPullConsumerTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamPushConsumerContractTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamPushConsumerTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamRetentionPolicyTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamSnapshotRestoreApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamStorageSelectionTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamStreamApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamStreamLifecycleApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamStreamListApiTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;
public class JetStreamStreamMessageApiTests

View File

@@ -1,4 +1,5 @@
using NATS.Server.JetStream.Models;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests;

View File

@@ -7,6 +7,7 @@ using NATS.Server.Auth;
using NATS.Server.Configuration;
using NATS.Server.LeafNodes;
using NATS.Server.Subscriptions;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.LeafNodes;

View File

@@ -7,6 +7,7 @@ using NATS.Server.Auth;
using NATS.Server.Configuration;
using NATS.Server.LeafNodes;
using NATS.Server.Subscriptions;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.LeafNodes;

View File

@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging.Abstractions;
using NATS.Client.Core;
using NATS.Server.Configuration;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.LeafNodes;

View File

@@ -1,4 +1,5 @@
using NATS.Client.Core;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.LeafNodes;

View File

@@ -11,14 +11,14 @@ public class LeafProtocolTests
[Fact]
public async Task Leaf_link_propagates_subscription_and_message_flow()
{
await using var fx = await LeafFixture.StartHubSpokeAsync();
await using var fx = await LeafProtocolTestFixture.StartHubSpokeAsync();
await fx.SubscribeSpokeAsync("leaf.>");
await fx.PublishHubAsync("leaf.msg", "x");
(await fx.ReadSpokeMessageAsync()).ShouldContain("x");
}
}
internal sealed class LeafFixture : IAsyncDisposable
internal sealed class LeafProtocolTestFixture : IAsyncDisposable
{
private readonly NatsServer _hub;
private readonly NatsServer _spoke;
@@ -27,7 +27,7 @@ internal sealed class LeafFixture : IAsyncDisposable
private Socket? _spokeSubscriber;
private Socket? _hubPublisher;
private LeafFixture(NatsServer hub, NatsServer spoke, CancellationTokenSource hubCts, CancellationTokenSource spokeCts)
private LeafProtocolTestFixture(NatsServer hub, NatsServer spoke, CancellationTokenSource hubCts, CancellationTokenSource spokeCts)
{
_hub = hub;
_spoke = spoke;
@@ -35,7 +35,7 @@ internal sealed class LeafFixture : IAsyncDisposable
_spokeCts = spokeCts;
}
public static async Task<LeafFixture> StartHubSpokeAsync()
public static async Task<LeafProtocolTestFixture> StartHubSpokeAsync()
{
var hubOptions = new NatsOptions
{
@@ -74,7 +74,7 @@ internal sealed class LeafFixture : IAsyncDisposable
while (!timeout.IsCancellationRequested && (hub.Stats.Leafs == 0 || spoke.Stats.Leafs == 0))
await Task.Delay(50, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
return new LeafFixture(hub, spoke, hubCts, spokeCts);
return new LeafProtocolTestFixture(hub, spoke, hubCts, spokeCts);
}
public async Task SubscribeSpokeAsync(string subject)

View File

@@ -22,11 +22,7 @@
<Using Include="Shouldly" />
</ItemGroup>
<ItemGroup>
<None Update="TestData\**\*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NATS.Server\NATS.Server.csproj" />
<ProjectReference Include="..\NATS.Server.TestUtilities\NATS.Server.TestUtilities.csproj" />
</ItemGroup>

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities.Parity;
namespace NATS.Server.Tests.Parity;
public class JetStreamParityTruthMatrixTests

View File

@@ -1,3 +1,5 @@
using NATS.Server.TestUtilities.Parity;
namespace NATS.Server.Tests.Parity;
public class NatsStrictCapabilityInventoryTests

View File

@@ -12,7 +12,8 @@ using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Consumers;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;
using ClusterFixture = NATS.Server.Tests.JetStream.Cluster.JetStreamClusterFixture;
using ClusterFixture = NATS.Server.TestUtilities.JetStreamClusterFixture;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.Stress;