# Test Project Split Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers-extended-cc:executing-plans to implement this plan task-by-task. **Goal:** Split the monolithic `NATS.Server.Tests` (609 files) into 10 feature-focused test projects + 1 shared test utilities library. **Architecture:** Create `NATS.Server.TestUtilities` as a class library with deduplicated helpers and shared fixtures. Then extract test files into subsystem-specific test projects one at a time, smallest first. Each extraction creates a new `.csproj`, moves files with `git mv`, updates namespaces, adds to the solution, and verifies build+test before proceeding to the next. **Tech Stack:** .NET 10, xUnit 3, Shouldly, NSubstitute, Central Package Management --- ### Task 0: Create NATS.Server.TestUtilities project **Files:** - Create: `tests/NATS.Server.TestUtilities/NATS.Server.TestUtilities.csproj` - Create: `tests/NATS.Server.TestUtilities/TestPortAllocator.cs` - Create: `tests/NATS.Server.TestUtilities/SocketTestHelper.cs` - Modify: `tests/NATS.Server.Tests/NATS.Server.Tests.csproj` (add ProjectReference) - Modify: `NatsDotNet.slnx` (add project) **Step 1: Create the TestUtilities csproj** ```xml false ``` **Step 2: Create TestPortAllocator.cs** ```csharp // tests/NATS.Server.TestUtilities/TestPortAllocator.cs using System.Net; using System.Net.Sockets; namespace NATS.Server.TestUtilities; public static class TestPortAllocator { public static int GetFreePort() { using var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock.Bind(new IPEndPoint(IPAddress.Loopback, 0)); return ((IPEndPoint)sock.LocalEndPoint!).Port; } } ``` **Step 3: Create SocketTestHelper.cs** ```csharp // tests/NATS.Server.TestUtilities/SocketTestHelper.cs using System.Net.Sockets; using System.Text; namespace NATS.Server.TestUtilities; public static class SocketTestHelper { public static async Task ReadUntilAsync(Socket sock, string expected, int timeoutMs = 5000) { using var cts = new CancellationTokenSource(timeoutMs); var sb = new StringBuilder(); var buf = new byte[4096]; while (!sb.ToString().Contains(expected, StringComparison.Ordinal)) { var n = await sock.ReceiveAsync(buf, SocketFlags.None, cts.Token); if (n == 0) break; sb.Append(Encoding.ASCII.GetString(buf, 0, n)); } return sb.ToString(); } } ``` **Step 4: Add ProjectReference to existing NATS.Server.Tests** Add to `tests/NATS.Server.Tests/NATS.Server.Tests.csproj` inside the `` with `ProjectReference`: ```xml ``` **Step 5: Add TestUtilities to solution file** In `NatsDotNet.slnx`, inside `` add: ```xml ``` **Step 6: Build to verify** Run: `dotnet build` Expected: SUCCESS — TestUtilities compiles, NATS.Server.Tests still compiles. **Step 7: Commit** ```bash git add tests/NATS.Server.TestUtilities/ NatsDotNet.slnx tests/NATS.Server.Tests/NATS.Server.Tests.csproj git commit -m "feat: create NATS.Server.TestUtilities with shared helpers" ``` --- ### Task 1: Move shared fixtures and parity utilities to TestUtilities **Files:** - Move: `tests/NATS.Server.Tests/JetStreamApiFixture.cs` → `tests/NATS.Server.TestUtilities/JetStreamApiFixture.cs` - Move: `tests/NATS.Server.Tests/JetStream/Cluster/JetStreamClusterFixture.cs` → `tests/NATS.Server.TestUtilities/JetStreamClusterFixture.cs` - Move: `tests/NATS.Server.Tests/LeafNodes/LeafFixture.cs` → `tests/NATS.Server.TestUtilities/LeafFixture.cs` - Move: `tests/NATS.Server.Tests/Parity/NatsCapabilityInventory.cs` → `tests/NATS.Server.TestUtilities/Parity/NatsCapabilityInventory.cs` - Move: `tests/NATS.Server.Tests/Parity/ParityRowInspector.cs` → `tests/NATS.Server.TestUtilities/Parity/ParityRowInspector.cs` - Move: `tests/NATS.Server.Tests/Parity/JetStreamParityTruthMatrix.cs` → `tests/NATS.Server.TestUtilities/Parity/JetStreamParityTruthMatrix.cs` - Move: `tests/NATS.Server.Tests/TestData/*` → `tests/NATS.Server.TestUtilities/TestData/*` **Step 1: Move files with git mv** ```bash cd tests git mv NATS.Server.Tests/JetStreamApiFixture.cs NATS.Server.TestUtilities/ git mv NATS.Server.Tests/JetStream/Cluster/JetStreamClusterFixture.cs NATS.Server.TestUtilities/ git mv NATS.Server.Tests/LeafNodes/LeafFixture.cs NATS.Server.TestUtilities/ mkdir -p NATS.Server.TestUtilities/Parity git mv NATS.Server.Tests/Parity/NatsCapabilityInventory.cs NATS.Server.TestUtilities/Parity/ git mv NATS.Server.Tests/Parity/ParityRowInspector.cs NATS.Server.TestUtilities/Parity/ git mv NATS.Server.Tests/Parity/JetStreamParityTruthMatrix.cs NATS.Server.TestUtilities/Parity/ mkdir -p NATS.Server.TestUtilities/TestData git mv NATS.Server.Tests/TestData/* NATS.Server.TestUtilities/TestData/ ``` **Step 2: Update namespaces in moved files** Change `namespace NATS.Server.Tests;` → `namespace NATS.Server.TestUtilities;` in each moved file. For parity files: `namespace NATS.Server.TestUtilities.Parity;` For fixtures in subfolders that had sub-namespaces (e.g. `NATS.Server.Tests.JetStream.Cluster`), update to `NATS.Server.TestUtilities;`. **Step 3: Make fixture classes public** The moved fixtures (`JetStreamApiFixture`, `JetStreamClusterFixture`, `LeafFixture`) are likely `internal`. Change them to `public` so test projects can access them. **Step 4: Add `using NATS.Server.TestUtilities;` to files that reference moved fixtures** All files that reference `JetStreamApiFixture`, `JetStreamClusterFixture`, `LeafFixture`, or parity utilities need the new using directive. This is ~52 files for JetStreamApiFixture, ~20 for cluster fixture, ~5 for LeafFixture. **Step 5: Remove TestData entry from NATS.Server.Tests.csproj** Remove the `` item since TestData moved to TestUtilities. **Step 6: Build and run tests** Run: `dotnet build && dotnet test tests/NATS.Server.Tests --no-build` Expected: All tests pass — fixtures resolved from TestUtilities. **Step 7: Commit** ```bash git add -A git commit -m "refactor: move shared fixtures and parity utilities to TestUtilities" ``` --- ### Task 2: Extract NATS.Server.Transport.Tests (~25 files) **Files:** - Create: `tests/NATS.Server.Transport.Tests/NATS.Server.Transport.Tests.csproj` - Move: Root files: OcspConfigTests.cs, OcspStaplingTests.cs, TlsConnectionWrapperTests.cs, TlsHelperTests.cs, TlsMapAuthenticatorTests.cs, TlsOcspParityBatch1Tests.cs, TlsOcspParityBatch2Tests.cs, TlsRateLimiterTests.cs, TlsServerTests.cs - Move: `WebSocket/` folder (15 files) - Move: `Networking/` folder (1 file) - Modify: `NatsDotNet.slnx` **Step 1: Create the csproj** ```xml false ``` **Step 2: Move files with git mv** ```bash cd tests mkdir -p NATS.Server.Transport.Tests git mv NATS.Server.Tests/OcspConfigTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/OcspStaplingTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsConnectionWrapperTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsHelperTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsMapAuthenticatorTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsOcspParityBatch1Tests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsOcspParityBatch2Tests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsRateLimiterTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/TlsServerTests.cs NATS.Server.Transport.Tests/ git mv NATS.Server.Tests/WebSocket NATS.Server.Transport.Tests/WebSocket git mv NATS.Server.Tests/Networking NATS.Server.Transport.Tests/Networking ``` **Step 3: Update namespaces** In all moved files, change: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Transport.Tests;` - `namespace NATS.Server.Tests.WebSocket;` → `namespace NATS.Server.Transport.Tests.WebSocket;` - `namespace NATS.Server.Tests.Networking;` → `namespace NATS.Server.Transport.Tests.Networking;` **Step 4: Replace private GetFreePort/ReadUntilAsync with TestUtilities calls** In each moved file that has `private static int GetFreePort()` or `private static async Task ReadUntilAsync(...)`: - Delete the private method - Add `using NATS.Server.TestUtilities;` - Replace `GetFreePort()` → `TestPortAllocator.GetFreePort()` - Replace `ReadUntilAsync(` → `SocketTestHelper.ReadUntilAsync(` **Step 5: Add to solution file** In `NatsDotNet.slnx`, inside `/tests/`: ```xml ``` **Step 6: Build and test** Run: `dotnet build && dotnet test tests/NATS.Server.Transport.Tests --no-build` Expected: All Transport tests pass. Run: `dotnet test tests/NATS.Server.Tests --no-build` Expected: Remaining tests still pass. **Step 7: Commit** ```bash git add -A git commit -m "refactor: extract NATS.Server.Transport.Tests project" ``` --- ### Task 3: Extract NATS.Server.Mqtt.Tests (~30 files) **Files:** - Create: `tests/NATS.Server.Mqtt.Tests/NATS.Server.Mqtt.Tests.csproj` - Move: Root file: MqttPersistenceTests.cs - Move: `Mqtt/` folder (28 files) **Step 1: Create csproj** (same template as Transport, no Serilog needed) **Step 2: Move files** ```bash cd tests mkdir -p NATS.Server.Mqtt.Tests git mv NATS.Server.Tests/MqttPersistenceTests.cs NATS.Server.Mqtt.Tests/ git mv NATS.Server.Tests/Mqtt NATS.Server.Mqtt.Tests/Mqtt ``` **Step 3: Update namespaces** - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Mqtt.Tests;` - `namespace NATS.Server.Tests.Mqtt;` → `namespace NATS.Server.Mqtt.Tests.Mqtt;` **Step 4: Replace duplicated helpers with TestUtilities calls** (same pattern as Task 2) **Step 5: Add to solution file** **Step 6: Build and test** Run: `dotnet build && dotnet test tests/NATS.Server.Mqtt.Tests --no-build` **Step 7: Commit** ```bash git add -A git commit -m "refactor: extract NATS.Server.Mqtt.Tests project" ``` --- ### Task 4: Extract NATS.Server.Gateways.Tests (~25 files) **Files:** - Create: `tests/NATS.Server.Gateways.Tests/NATS.Server.Gateways.Tests.csproj` - Move: Root files: GatewayAdvancedRemapRuntimeTests.cs, GatewayAdvancedSemanticsTests.cs, GatewayLeafBootstrapTests.cs, GatewayProtocolTests.cs - Move: `Gateways/` folder (21 files) **Steps:** Same pattern as Tasks 2-3. Namespace changes: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Gateways.Tests;` - `namespace NATS.Server.Tests.Gateways;` → `namespace NATS.Server.Gateways.Tests.Gateways;` May need `NATS.Client.Core` package if any gateway test uses `NatsConnection`. **Commit:** `git commit -m "refactor: extract NATS.Server.Gateways.Tests project"` --- ### Task 5: Extract NATS.Server.LeafNodes.Tests (~30 files) **Files:** - Create: `tests/NATS.Server.LeafNodes.Tests/NATS.Server.LeafNodes.Tests.csproj` - Move: Root files: LeafAdvancedSemanticsTests.cs, LeafProtocolTests.cs - Move: `LeafNodes/` folder (26 files) — note: `LeafFixture.cs` already moved to TestUtilities - Move: `LeafNode/` folder (1 file) **Steps:** Same pattern. The `LeafFixture` reference now comes from TestUtilities — add `using NATS.Server.TestUtilities;`. Namespace changes: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.LeafNodes.Tests;` - `namespace NATS.Server.Tests.LeafNodes;` → `namespace NATS.Server.LeafNodes.Tests.LeafNodes;` - `namespace NATS.Server.Tests.LeafNode;` → `namespace NATS.Server.LeafNodes.Tests.LeafNode;` **Commit:** `git commit -m "refactor: extract NATS.Server.LeafNodes.Tests project"` --- ### Task 6: Extract NATS.Server.Clustering.Tests (~30 files) **Files:** - Create: `tests/NATS.Server.Clustering.Tests/NATS.Server.Clustering.Tests.csproj` - Move: Root files: RouteHandshakeTests.cs, RoutePoolTests.cs, RouteRmsgForwardingTests.cs, RouteSubscriptionPropagationTests.cs, RouteWireSubscriptionProtocolTests.cs, ImplicitDiscoveryTests.cs, InterServerAccountProtocolTests.cs - Move: `Routes/` folder (21 files) - Move: `Route/` folder (1 file) **Steps:** Same pattern. Namespace changes: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Clustering.Tests;` - `namespace NATS.Server.Tests.Routes;` → `namespace NATS.Server.Clustering.Tests.Routes;` - `namespace NATS.Server.Tests.Route;` → `namespace NATS.Server.Clustering.Tests.Route;` **Commit:** `git commit -m "refactor: extract NATS.Server.Clustering.Tests project"` --- ### Task 7: Extract NATS.Server.Raft.Tests (~45 files) **Files:** - Create: `tests/NATS.Server.Raft.Tests/NATS.Server.Raft.Tests.csproj` - Move: Root files: RaftConsensusAdvancedParityTests.cs, RaftElectionTests.cs, RaftMembershipParityTests.cs, RaftReplicationTests.cs, RaftSafetyContractTests.cs, RaftSnapshotCatchupTests.cs, RaftSnapshotTransferParityTests.cs, RaftTransportPersistenceTests.cs - Move: `Raft/` folder (36 files) **Steps:** Same pattern. Namespace changes: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Raft.Tests;` - `namespace NATS.Server.Tests.Raft;` → `namespace NATS.Server.Raft.Tests.Raft;` **Commit:** `git commit -m "refactor: extract NATS.Server.Raft.Tests project"` --- ### Task 8: Extract NATS.Server.Monitoring.Tests (~35 files) **Files:** - Create: `tests/NATS.Server.Monitoring.Tests/NATS.Server.Monitoring.Tests.csproj` - Move: Root files: EventSystemTests.cs, JszMonitorTests.cs, MonitorClusterEndpointTests.cs, MonitorModelTests.cs, MonitorTests.cs, SubszTests.cs, SystemEventsTests.cs, SystemRequestReplyTests.cs - Move: `Monitoring/` folder (21 files) - Move: `Events/` folder (10 files) **Steps:** Same pattern. Needs `NATS.Client.Core` package for integration tests. Namespace changes: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Monitoring.Tests;` - `namespace NATS.Server.Tests.Monitoring;` → `namespace NATS.Server.Monitoring.Tests.Monitoring;` - `namespace NATS.Server.Tests.Events;` → `namespace NATS.Server.Monitoring.Tests.Events;` **Commit:** `git commit -m "refactor: extract NATS.Server.Monitoring.Tests project"` --- ### Task 9: Extract NATS.Server.Auth.Tests (~50 files) **Files:** - Create: `tests/NATS.Server.Auth.Tests/NATS.Server.Auth.Tests.csproj` - Move: Root files: AccountIsolationTests.cs, AccountResolverTests.cs, AccountStatsTests.cs, AccountTests.cs, AuthConfigTests.cs, AuthIntegrationTests.cs, AuthProtocolTests.cs, AuthServiceTests.cs, ClientPermissionsTests.cs, JwtAuthenticatorTests.cs, JwtTests.cs, NKeyAuthenticatorTests.cs, NKeyIntegrationTests.cs, PermissionIntegrationTests.cs, PermissionLruCacheTests.cs, PermissionTemplateTests.cs, SimpleUserPasswordAuthenticatorTests.cs, TokenAuthenticatorTests.cs, UserPasswordAuthenticatorTests.cs, ImportExportTests.cs - Move: `Auth/` folder (25 files) - Move: `Accounts/` folder (5 files) **Steps:** Same pattern. Needs `NATS.NKeys` and `NATS.Client.Core` packages. Namespace changes: - `namespace NATS.Server.Tests;` → `namespace NATS.Server.Auth.Tests;` - `namespace NATS.Server.Tests.Auth;` → `namespace NATS.Server.Auth.Tests.Auth;` - `namespace NATS.Server.Tests.Accounts;` → `namespace NATS.Server.Auth.Tests.Accounts;` **Commit:** `git commit -m "refactor: extract NATS.Server.Auth.Tests project"` --- ### Task 10: Extract NATS.Server.JetStream.Tests (~220 files) **Files:** - Create: `tests/NATS.Server.JetStream.Tests/NATS.Server.JetStream.Tests.csproj` - Move: All root `JetStream*` files (~55 files) - Move: Root storage files: FileStoreTests.cs, FileStoreEncryptionTests.cs, MemStoreTests.cs, StreamStoreContractTests.cs, MirrorSourceRetryTests.cs, ClusterJetStreamConfigProcessorTests.cs - Move: `JetStream/` folder and all sub-folders (163 files) — note: `JetStreamClusterFixture.cs` already in TestUtilities **Step 1: Create csproj with JetStream-specific additions** ```xml false $(DefineConstants);JETSTREAM_INTEGRATION_MATRIX ``` **Step 2: Move files** — this is the largest move. Use a script: ```bash cd tests mkdir -p NATS.Server.JetStream.Tests # Move JetStream subfolder (preserves internal structure) git mv NATS.Server.Tests/JetStream NATS.Server.JetStream.Tests/JetStream # Move root JetStream* files for f in NATS.Server.Tests/JetStream*.cs; do git mv "$f" NATS.Server.JetStream.Tests/ done # Move storage-related root files git mv NATS.Server.Tests/FileStoreTests.cs NATS.Server.JetStream.Tests/ git mv NATS.Server.Tests/FileStoreEncryptionTests.cs NATS.Server.JetStream.Tests/ git mv NATS.Server.Tests/MemStoreTests.cs NATS.Server.JetStream.Tests/ git mv NATS.Server.Tests/StreamStoreContractTests.cs NATS.Server.JetStream.Tests/ git mv NATS.Server.Tests/MirrorSourceRetryTests.cs NATS.Server.JetStream.Tests/ git mv NATS.Server.Tests/ClusterJetStreamConfigProcessorTests.cs NATS.Server.JetStream.Tests/ ``` **Step 3: Update namespaces** - `namespace NATS.Server.Tests;` → `namespace NATS.Server.JetStream.Tests;` (root files) - `namespace NATS.Server.Tests.JetStream;` → `namespace NATS.Server.JetStream.Tests.JetStream;` - All JetStream sub-namespaces follow the pattern (e.g., `NATS.Server.Tests.JetStream.Cluster` → `NATS.Server.JetStream.Tests.JetStream.Cluster`) **Step 4: Update fixture references** Files using `JetStreamApiFixture` or `JetStreamClusterFixture` need `using NATS.Server.TestUtilities;` since the fixtures moved there in Task 1. **Step 5: Replace duplicated helpers with TestUtilities calls** **Step 6: Add to solution, build, test** Run: `dotnet build && dotnet test tests/NATS.Server.JetStream.Tests --no-build` **Step 7: Commit** ```bash git add -A git commit -m "refactor: extract NATS.Server.JetStream.Tests project" ``` --- ### Task 11: Rename remaining project to NATS.Server.Core.Tests **Files:** - Rename: `tests/NATS.Server.Tests/` → `tests/NATS.Server.Core.Tests/` - Rename: `tests/NATS.Server.Tests/NATS.Server.Tests.csproj` → `tests/NATS.Server.Core.Tests/NATS.Server.Core.Tests.csproj` - Modify: `NatsDotNet.slnx` (update path) **Step 1: Rename directory and csproj** ```bash cd tests git mv NATS.Server.Tests NATS.Server.Core.Tests cd NATS.Server.Core.Tests git mv NATS.Server.Tests.csproj NATS.Server.Core.Tests.csproj ``` **Step 2: Update solution file** Replace `tests/NATS.Server.Tests/NATS.Server.Tests.csproj` with `tests/NATS.Server.Core.Tests/NATS.Server.Core.Tests.csproj`. **Step 3: Clean up csproj** Remove the `JETSTREAM_INTEGRATION_MATRIX` DefineConstants (that moved to JetStream.Tests). Remove any package references only needed by extracted projects (e.g., `NATS.NKeys` if only auth tests needed it). Keep `NATS.Client.Core` and `Serilog.Sinks.File`. **Step 4: Update namespaces** Change `namespace NATS.Server.Tests;` → `namespace NATS.Server.Core.Tests;` in all remaining files. Update sub-namespaces: `NATS.Server.Tests.Configuration` → `NATS.Server.Core.Tests.Configuration`, etc. **Step 5: Replace duplicated helpers with TestUtilities calls** **Step 6: Build and test all projects** Run: `dotnet build && dotnet test` Expected: All projects build and all tests pass. **Step 7: Commit** ```bash git add -A git commit -m "refactor: rename remaining tests to NATS.Server.Core.Tests" ``` --- ### Task 12: Final verification and cleanup **Step 1: Run full test suite** ```bash dotnet test -v normal 2>&1 | tail -20 ``` Expected: All test projects discovered and run. Total test count should match original (~6,409 parameterized tests). **Step 2: Verify each project runs independently** ```bash dotnet test tests/NATS.Server.Core.Tests dotnet test tests/NATS.Server.Auth.Tests dotnet test tests/NATS.Server.JetStream.Tests dotnet test tests/NATS.Server.Raft.Tests dotnet test tests/NATS.Server.Clustering.Tests dotnet test tests/NATS.Server.Gateways.Tests dotnet test tests/NATS.Server.LeafNodes.Tests dotnet test tests/NATS.Server.Mqtt.Tests dotnet test tests/NATS.Server.Monitoring.Tests dotnet test tests/NATS.Server.Transport.Tests dotnet test tests/NATS.E2E.Tests ``` **Step 3: Verify solution structure** ```bash dotnet sln NatsDotNet.slnx list ``` Expected: 13 projects listed (2 src + 11 test). **Step 4: Check for orphaned files** ```bash find tests/NATS.Server.Core.Tests -name "*.cs" -not -path "*/obj/*" -not -path "*/bin/*" | wc -l ``` Should be ~75 files. Any file that doesn't belong in Core should be moved to its correct project. **Step 5: Clean build artifacts and rebuild from scratch** ```bash dotnet clean && dotnet build && dotnet test ``` **Step 6: Commit any cleanup** ```bash git add -A git commit -m "chore: final cleanup after test project split" ```