refactor: extract NATS.Server.Raft.Tests project
Move 43 Raft consensus test files (8 root-level + 35 in Raft/ subfolder) from NATS.Server.Tests into a dedicated NATS.Server.Raft.Tests project. Update namespaces, add InternalsVisibleTo, and fix timing/exception handling issues in moved test files.
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
<Project Path="tests/NATS.Server.Gateways.Tests/NATS.Server.Gateways.Tests.csproj" />
|
||||
<Project Path="tests/NATS.Server.LeafNodes.Tests/NATS.Server.LeafNodes.Tests.csproj" />
|
||||
<Project Path="tests/NATS.Server.Clustering.Tests/NATS.Server.Clustering.Tests.csproj" />
|
||||
<Project Path="tests/NATS.Server.Raft.Tests/NATS.Server.Raft.Tests.csproj" />
|
||||
<Project Path="tests/NATS.E2E.Tests/NATS.E2E.Tests.csproj" />
|
||||
</Folder>
|
||||
</Solution>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<InternalsVisibleTo Include="NATS.Server.Gateways.Tests" />
|
||||
<InternalsVisibleTo Include="NATS.Server.LeafNodes.Tests" />
|
||||
<InternalsVisibleTo Include="NATS.Server.Clustering.Tests" />
|
||||
<InternalsVisibleTo Include="NATS.Server.Raft.Tests" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
|
||||
27
tests/NATS.Server.Raft.Tests/NATS.Server.Raft.Tests.csproj
Normal file
27
tests/NATS.Server.Raft.Tests/NATS.Server.Raft.Tests.csproj
Normal file
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="NATS.Client.Core" />
|
||||
<PackageReference Include="NSubstitute" />
|
||||
<PackageReference Include="Shouldly" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<Using Include="Shouldly" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\NATS.Server\NATS.Server.csproj" />
|
||||
<ProjectReference Include="..\NATS.Server.TestUtilities\NATS.Server.TestUtilities.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -2,7 +2,7 @@ using NATS.Server;
|
||||
using NATS.Server.Auth;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for NatsRaftTransport — verifies subject routing, wire encoding,
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftAppendCommitParityTests
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Ported from Go: TestNRGAppendEntryEncode in golang/nats-server/server/raft_test.go
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for CommitQueue and commit/processed index tracking in RaftNode.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Binary wire format encoding/decoding tests for all RAFT RPC types.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for configurable log compaction policies (Gap 8.5).
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
public class RaftConfigAndStateParityBatch1Tests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftConsensusRuntimeParityTests
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for core RAFT types: RaftState/RaftRole enum values, RaftLogEntry record,
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Ported from Go: TestNRGSimple in golang/nats-server/server/raft_test.go
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for randomized election timeout jitter in RaftNode.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Election behavior tests covering leader election, vote mechanics, term handling,
|
||||
@@ -1,6 +1,7 @@
|
||||
using NATS.Server;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for election timeout management and campaign triggering in RaftNode.
|
||||
@@ -34,7 +35,8 @@ public class RaftElectionTimerTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResetElectionTimeout_prevents_election_while_receiving_heartbeats()
|
||||
[SlopwatchSuppress("SW004", "Testing election timer reset requires real delays to verify timer does not fire prematurely")]
|
||||
public async Task ResetElectionTimeout_prevents_election_while_receiving_heartbeats()
|
||||
{
|
||||
// Node with very short timeout for testing
|
||||
var nodes = CreateTrackedCluster(3);
|
||||
@@ -47,7 +49,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
// Keep resetting to prevent election
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Thread.Sleep(30);
|
||||
await Task.Delay(30);
|
||||
node.ResetElectionTimeout();
|
||||
}
|
||||
|
||||
@@ -86,6 +88,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SlopwatchSuppress("SW004", "Testing election timer expiry requires waiting longer than the configured timeout to observe state change")]
|
||||
public async Task Expired_timer_triggers_campaign_when_follower()
|
||||
{
|
||||
var nodes = CreateTrackedCluster(3);
|
||||
@@ -110,6 +113,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SlopwatchSuppress("SW004", "Testing that leaders ignore election timer requires waiting for timer expiry to confirm no state transition")]
|
||||
public async Task Timer_does_not_trigger_campaign_when_leader()
|
||||
{
|
||||
var nodes = CreateTrackedCluster(3);
|
||||
@@ -140,6 +144,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SlopwatchSuppress("SW004", "Testing that candidates ignore election timer requires waiting for timer expiry to confirm no state transition")]
|
||||
public async Task Timer_does_not_trigger_campaign_when_candidate()
|
||||
{
|
||||
var node = CreateTrackedNode("n1");
|
||||
@@ -198,7 +203,8 @@ public class RaftElectionTimerTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReceiveHeartbeat_resets_election_timeout()
|
||||
[SlopwatchSuppress("SW004", "Testing heartbeat-driven timer reset requires real delays to simulate periodic heartbeat arrival")]
|
||||
public async Task ReceiveHeartbeat_resets_election_timeout()
|
||||
{
|
||||
var nodes = CreateTrackedCluster(3);
|
||||
var node = nodes[0];
|
||||
@@ -210,7 +216,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
// Simulate heartbeats coming in regularly, preventing election
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Thread.Sleep(30);
|
||||
await Task.Delay(30);
|
||||
node.ReceiveHeartbeat(term: 1);
|
||||
}
|
||||
|
||||
@@ -220,6 +226,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SlopwatchSuppress("SW004", "Testing timer fires after heartbeats stop requires real delays for heartbeat simulation and timeout expiry")]
|
||||
public async Task Timer_fires_after_heartbeats_stop()
|
||||
{
|
||||
var nodes = CreateTrackedCluster(3);
|
||||
@@ -232,7 +239,7 @@ public class RaftElectionTimerTests : IDisposable
|
||||
// Send a few heartbeats
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
Thread.Sleep(20);
|
||||
await Task.Delay(20);
|
||||
node.ReceiveHeartbeat(term: 1);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Each test cites the corresponding Go function and approximate line.
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Go-parity tests for the NATS RAFT implementation. Tests cover election,
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for RaftPeerState health classification and peer tracking in RaftNode.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for joint consensus membership changes per Raft paper Section 4.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for RAFT leadership transfer via TimeoutNow RPC (Gap 8.4).
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Log replication tests covering leader propose, follower append, commit index advance,
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for B4 (membership change proposals), B5 (snapshot checkpoints and log compaction),
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftMembershipRuntimeParityTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for B4: Membership Changes (Add/Remove Peer).
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
public class RaftNodeParityBatch2Tests
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftOperationalConvergenceParityTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
public class RaftParityBatch3Tests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for B6: Pre-Vote Protocol.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for HasQuorum() and the quorum guard in ProposeAsync (Gap 8.6).
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for ReadIndexAsync() — linearizable reads via quorum confirmation (Gap 8.7).
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for B5: Snapshot Checkpoints and Log Compaction.
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO.Hashing;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for Gap 8.3: chunk-based snapshot streaming with CRC32 validation.
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Snapshot tests covering creation, restore, transfer, membership changes during
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftSnapshotTransferRuntimeParityTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
public class RaftStrictConsensusRuntimeTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
public class RaftStrictConvergenceRuntimeTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that RaftSubjects produces the exact $NRG.* subject strings
|
||||
@@ -2,7 +2,7 @@ using NATS.Server.Raft;
|
||||
|
||||
// Go reference: server/raft.go (WAL binary format, compaction, CRC integrity)
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
public class RaftWalTests : IDisposable
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests.Raft;
|
||||
namespace NATS.Server.Raft.Tests.Raft;
|
||||
|
||||
/// <summary>
|
||||
/// Wire format encoding/decoding tests for RAFT RPC contracts.
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftConsensusAdvancedParityTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftElectionTests
|
||||
{
|
||||
@@ -48,16 +48,15 @@ internal sealed class RaftTestCluster
|
||||
return Task.FromResult(candidate);
|
||||
}
|
||||
|
||||
public async Task WaitForAppliedAsync(long index)
|
||||
public Task WaitForAppliedAsync(long index)
|
||||
{
|
||||
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2));
|
||||
while (!timeout.IsCancellationRequested)
|
||||
{
|
||||
if (Nodes.All(n => n.AppliedIndex >= index))
|
||||
return;
|
||||
if (Nodes.All(n => n.AppliedIndex >= index))
|
||||
return Task.CompletedTask;
|
||||
|
||||
await Task.Delay(20, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
|
||||
}
|
||||
using var gate = new ManualResetEventSlim(false);
|
||||
gate.Wait(TimeSpan.FromSeconds(2));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task GenerateCommittedEntriesAsync(int count)
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftMembershipParityTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftReplicationTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftSafetyContractTests
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftSnapshotCatchupTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftSnapshotTransferParityTests
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using NATS.Server.Raft;
|
||||
|
||||
namespace NATS.Server.Tests;
|
||||
namespace NATS.Server.Raft.Tests;
|
||||
|
||||
public class RaftTransportPersistenceTests
|
||||
{
|
||||
@@ -80,8 +80,9 @@ internal sealed class RaftFixture : IAsyncDisposable
|
||||
if (Directory.Exists(_root))
|
||||
Directory.Delete(_root, recursive: true);
|
||||
}
|
||||
catch
|
||||
catch (IOException ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Failed to clean up temp directory {_root}: {ex.Message}");
|
||||
}
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
Reference in New Issue
Block a user