docs: add design doc for splitting NATS.Server.Tests into feature-focused projects
Splits the 609-file monolithic test project into 10 subsystem test projects plus a shared TestUtilities library for developer ergonomics.
This commit is contained in:
222
docs/plans/2026-03-12-test-project-split-design.md
Normal file
222
docs/plans/2026-03-12-test-project-split-design.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# Test Project Split Design
|
||||
|
||||
**Date:** 2026-03-12
|
||||
**Goal:** Split `NATS.Server.Tests` (609 files) into feature-focused test projects for developer ergonomics — easier to run just the tests for the subsystem you're working on.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
tests/
|
||||
NATS.Server.TestUtilities/ # Shared helpers, fixtures, parity tools (class library)
|
||||
NATS.Server.Core.Tests/ # Client, server, parser, config, subscriptions, protocol
|
||||
NATS.Server.Auth.Tests/ # Auth, accounts, permissions, JWT, NKeys
|
||||
NATS.Server.JetStream.Tests/ # JetStream API, streams, consumers, storage, cluster
|
||||
NATS.Server.Raft.Tests/ # RAFT consensus
|
||||
NATS.Server.Clustering.Tests/ # Routes, cluster topology, inter-server protocol
|
||||
NATS.Server.Gateways.Tests/ # Gateway connections, interest modes
|
||||
NATS.Server.LeafNodes.Tests/ # Leaf node connections, hub-spoke
|
||||
NATS.Server.Mqtt.Tests/ # MQTT protocol bridge
|
||||
NATS.Server.Monitoring.Tests/ # Monitor endpoints, events, system events
|
||||
NATS.Server.Transport.Tests/ # WebSocket, TLS, OCSP, IO
|
||||
NATS.E2E.Tests/ # (existing, unchanged)
|
||||
```
|
||||
|
||||
## TestUtilities Contents
|
||||
|
||||
`NATS.Server.TestUtilities` is a **class library** (not a test project).
|
||||
|
||||
### Shared helpers (deduplicated)
|
||||
- `TestPortAllocator` — `GetFreePort()` (currently duplicated in ~51 files)
|
||||
- `SocketTestHelper` — `ReadUntilAsync()`, raw socket connect/read patterns (~25 files)
|
||||
- `ServerTestHelper` — common server startup/teardown patterns
|
||||
|
||||
### Shared fixtures
|
||||
- `JetStreamApiFixture` — moved from root (used by 52 JetStream test files)
|
||||
- `JetStreamClusterFixture` — consolidated from 2 duplicate definitions
|
||||
- `LeafFixture` — consolidated from 3 duplicate definitions
|
||||
|
||||
### Parity utilities (non-test)
|
||||
- `NatsCapabilityInventory.cs`
|
||||
- `ParityRowInspector.cs`
|
||||
- `JetStreamParityTruthMatrix.cs`
|
||||
|
||||
### TestData
|
||||
- `TestData/*.conf` files (copied to output directory)
|
||||
|
||||
## File-to-Project Mapping
|
||||
|
||||
### NATS.Server.Core.Tests (~75 files)
|
||||
|
||||
**Root-level:**
|
||||
ClientClosedReasonTests, ClientFlagsTests, ClientHeaderTests, ClientKindCommandMatrixTests, ClientKindProtocolRoutingTests, ClientKindTests, ClientLifecycleTests, ClientProtocolParityTests, ClientPubSubTests, ClientServerGoParityTests, ClientSlowConsumerTests, ClientTests, ClientTraceModeTests, ClientTraceTests, ClientUnsubTests, ConfigIntegrationTests, ConfigProcessorTests, ConfigReloadTests, ConfigRuntimeParityTests, FlushCoalescingTests, IntegrationTests, InternalClientTests, LoggingTests, MessageTraceTests, MsgTraceGoParityTests, NatsConfLexerTests, NatsConfParserTests, NatsHeaderParserTests, NatsOptionsTests, NoRespondersTests, ParserTests, ResponseRoutingTests, ResponseTrackerTests, RttTests, ServerConfigTests, ServerStatsTests, ServerTests, SignalHandlerTests, SlopwatchSuppressAttribute, SlowConsumerStallGateTests, StallGateTests, SubjectMatchTests, SubjectTransformIntegrationTests, SubjectTransformTests, SubListTests, VerboseModeTests, WriteLoopTests, WriteTimeoutTests, ConcurrencyStressTests
|
||||
|
||||
**Subfolders:** Configuration/ (14), Internal/ (8), IO/ (4), Protocol/ (7), Server/ (7), SubList/ (6), Subscriptions/ (6), Stress/ (3)
|
||||
|
||||
**Parity test files (from Parity/ folder):** NatsStrictCapabilityInventoryTests, JetStreamParityTruthMatrixTests, GoParityRunnerTests, InfrastructureGoParityTests, DifferencesParityClosureTests
|
||||
|
||||
### NATS.Server.Auth.Tests (~50 files)
|
||||
|
||||
**Root-level:**
|
||||
AccountIsolationTests, AccountResolverTests, AccountStatsTests, AccountTests, AuthConfigTests, AuthIntegrationTests, AuthProtocolTests, AuthServiceTests, ClientPermissionsTests, JwtAuthenticatorTests, JwtTests, NKeyAuthenticatorTests, NKeyIntegrationTests, PermissionIntegrationTests, PermissionLruCacheTests, PermissionTemplateTests, SimpleUserPasswordAuthenticatorTests, TokenAuthenticatorTests, UserPasswordAuthenticatorTests, ImportExportTests
|
||||
|
||||
**Subfolders:** Auth/ (25), Accounts/ (5)
|
||||
|
||||
### NATS.Server.JetStream.Tests (~220 files)
|
||||
|
||||
**Root-level:**
|
||||
All `JetStream*` files at root (~55), plus FileStoreTests, FileStoreEncryptionTests, MemStoreTests, StreamStoreContractTests, MirrorSourceRetryTests, ClusterJetStreamConfigProcessorTests
|
||||
|
||||
**Subfolders:** JetStream/ and all sub-folders (163 files)
|
||||
|
||||
### NATS.Server.Raft.Tests (~45 files)
|
||||
|
||||
**Root-level:** RaftConsensusAdvancedParityTests, RaftElectionTests, RaftMembershipParityTests, RaftReplicationTests, RaftSafetyContractTests, RaftSnapshotCatchupTests, RaftSnapshotTransferParityTests, RaftTransportPersistenceTests
|
||||
|
||||
**Subfolders:** Raft/ (36)
|
||||
|
||||
### NATS.Server.Clustering.Tests (~30 files)
|
||||
|
||||
**Root-level:** RouteHandshakeTests, RoutePoolTests, RouteRmsgForwardingTests, RouteSubscriptionPropagationTests, RouteWireSubscriptionProtocolTests, ImplicitDiscoveryTests, InterServerAccountProtocolTests
|
||||
|
||||
**Subfolders:** Routes/ (21), Route/ (1)
|
||||
|
||||
### NATS.Server.Gateways.Tests (~25 files)
|
||||
|
||||
**Root-level:** GatewayAdvancedRemapRuntimeTests, GatewayAdvancedSemanticsTests, GatewayLeafBootstrapTests, GatewayProtocolTests
|
||||
|
||||
**Subfolders:** Gateways/ (21)
|
||||
|
||||
### NATS.Server.LeafNodes.Tests (~30 files)
|
||||
|
||||
**Root-level:** LeafAdvancedSemanticsTests, LeafProtocolTests
|
||||
|
||||
**Subfolders:** LeafNodes/ (26), LeafNode/ (1)
|
||||
|
||||
### NATS.Server.Mqtt.Tests (~30 files)
|
||||
|
||||
**Root-level:** MqttPersistenceTests
|
||||
|
||||
**Subfolders:** Mqtt/ (28)
|
||||
|
||||
### NATS.Server.Monitoring.Tests (~35 files)
|
||||
|
||||
**Root-level:** EventSystemTests, JszMonitorTests, MonitorClusterEndpointTests, MonitorModelTests, MonitorTests, SubszTests, SystemEventsTests, SystemRequestReplyTests
|
||||
|
||||
**Subfolders:** Monitoring/ (21), Events/ (10)
|
||||
|
||||
### NATS.Server.Transport.Tests (~25 files)
|
||||
|
||||
**Root-level:** OcspConfigTests, OcspStaplingTests, TlsConnectionWrapperTests, TlsHelperTests, TlsMapAuthenticatorTests, TlsOcspParityBatch1Tests, TlsOcspParityBatch2Tests, TlsRateLimiterTests, TlsServerTests
|
||||
|
||||
**Subfolders:** WebSocket/ (15), Networking/ (1)
|
||||
|
||||
## Project File Template
|
||||
|
||||
Each test project follows the same base pattern:
|
||||
|
||||
```xml
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<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>
|
||||
```
|
||||
|
||||
**Project-specific package additions:**
|
||||
|
||||
| Project | Extra packages |
|
||||
|---------|---------------|
|
||||
| Auth.Tests | `NATS.NKeys` |
|
||||
| JetStream.Tests | `NATS.Client.Core`, `JETSTREAM_INTEGRATION_MATRIX` define constant |
|
||||
| Transport.Tests | `Serilog.Sinks.File` (if TLS tests use it) |
|
||||
| Core.Tests | `NATS.Client.Core`, `Serilog.Sinks.File` |
|
||||
| Monitoring.Tests | `NATS.Client.Core` |
|
||||
|
||||
**TestUtilities** is a plain class library:
|
||||
|
||||
```xml
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NATS.Client.Core" />
|
||||
<PackageReference Include="Shouldly" />
|
||||
<PackageReference Include="xunit" /> <!-- for IAsyncLifetime fixtures -->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="TestData\**\*" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\NATS.Server\NATS.Server.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Create TestUtilities
|
||||
- Create `NATS.Server.TestUtilities` project
|
||||
- Extract `GetFreePort()`, `ReadUntilAsync()` into shared helper classes
|
||||
- Move `JetStreamApiFixture`, consolidated `JetStreamClusterFixture`, consolidated `LeafFixture`
|
||||
- Move parity utility files (non-test) and TestData
|
||||
- Update the original `NATS.Server.Tests` to reference TestUtilities
|
||||
- Verify build + all tests pass
|
||||
|
||||
### Phase 2: Split projects one at a time (smallest first)
|
||||
1. Transport.Tests (~25 files)
|
||||
2. Mqtt.Tests (~30 files)
|
||||
3. Gateways.Tests (~25 files)
|
||||
4. LeafNodes.Tests (~30 files)
|
||||
5. Clustering.Tests (~30 files)
|
||||
6. Raft.Tests (~45 files)
|
||||
7. Monitoring.Tests (~35 files)
|
||||
8. Auth.Tests (~50 files)
|
||||
9. JetStream.Tests (~220 files)
|
||||
10. Core.Tests (rename remaining original project)
|
||||
|
||||
Each step:
|
||||
- Create the new `.csproj`
|
||||
- Move files with `git mv` to preserve history
|
||||
- Update namespaces to match new project name
|
||||
- Add to solution file
|
||||
- Remove files from old project
|
||||
- Build + test
|
||||
|
||||
### Phase 3: Cleanup
|
||||
- Delete the original `NATS.Server.Tests` project (now empty)
|
||||
- Verify `dotnet test` from solution root runs all projects
|
||||
- Verify CI still works
|
||||
|
||||
## Decisions
|
||||
|
||||
- **Namespaces updated** to match new project names (e.g., `NATS.Server.Auth.Tests`)
|
||||
- **Root-level files sorted** into matching subsystem projects by prefix/topic
|
||||
- **Storage files** (FileStore, MemStore, StreamStore) → JetStream project
|
||||
- **ImportExportTests** → Auth project
|
||||
- **InternalClientTests** → Core project
|
||||
- **Parity test files** → Core.Tests; parity utility classes → TestUtilities
|
||||
- **Stress test files** → Core.Tests (only 3-4 files, not worth a separate project)
|
||||
- **Trace files** → Core.Tests (tracing is a core feature)
|
||||
Reference in New Issue
Block a user