Systematic mapping of 3,451 Go test functions against .NET port reveals ~18% coverage. Design defines 4-phase hybrid dependency-first approach: Foundation (client/routing/sublist) -> Distributed substrate (RAFT/storage) -> JetStream depth -> Protocol surfaces (MQTT/JWT).
11 KiB
Go-to-.NET Systematic Test Parity Design
Date: 2026-02-23 Status: Approved Scope: Systematically map every Go NATS server test function to .NET equivalents, fill all gaps to achieve behavioral test parity.
1. Current State
The .NET port has all source code implemented (~170 source files, 236 test files, 867 passing tests). However, the Go reference has 3,451+ test functions across 88 test files. Systematic mapping reveals ~18% coverage of Go test intents.
Coverage Matrix
| Subsystem | Go Tests | .NET Tests | Coverage | Phase |
|---|---|---|---|---|
| Parser | 17 | 8 | 47% | A |
| SubList | 62 | 22 | 35% | A |
| Client | 82 | 3 | 4% | A |
| Server | 44 | 17 | 39% | A |
| Routes | 70 | 12 | 17% | A |
| Gateways | 88 | 9 | 10% | A |
| Leaf Nodes | 110 | 8 | 7% | A |
| Auth | 12 | 10 | 83% | A |
| Accounts | 64 | 18 | 28% | A |
| JetStream Core | 472 | 82 | 17% | C |
| JetStream Clustering | 503 | 4 | 1% | C |
| Storage | 269 | 2 | 1% | B |
| Config/Reload | 159 | 77 | 48% | B |
| Monitoring/Events | 184 | 28 | 15% | B |
| RAFT | 104 | 15 | 14% | B |
| MQTT | 123 | 8 | 7% | D |
| WebSocket | 61 | 66 | 108% | - |
| JWT | 88 | 61 | 69% | D |
| TOTAL | ~2,512 | ~454 | ~18% |
2. Architecture and Approach
Hybrid Dependency-First Phasing
Execute in 4 gated phases ordered by dependency criticality:
- Phase A (Foundation): Client, Parser, SubList, Server, Routes, Gateways, Leaf Nodes, Accounts (~440 tests)
- Phase B (Distributed Substrate): RAFT, Storage, Config/Reload, Monitoring/Events (~594 tests)
- Phase C (JetStream Depth): JetStream Core, JetStream Clustering (~889 tests)
- Phase D (Protocol Surfaces): MQTT, Auth/JWT hardening (~135 tests)
Test Philosophy
- Behavioral equivalence, not 1:1 test count parity. One .NET test may cover multiple Go tests if it preserves the same contract and failure detection power.
- Every Go test intent mapped. Maintain
go-dotnet-test-mapping.mdtracking every Go test function to .NET tests or explicit N/A rationale. - Primary KPI: Contract coverage by subsystem, not raw test count.
- Test-first: Write failing test, then implement/fix, then verify pass.
Execution Model
- Each phase is a gate — must pass full
dotnet testbefore advancing. - Within phases, subsystems are independent and run in parallel via subagents.
- Use
model: "sonnet"for straightforward test porting,model: "opus"for complex protocol/concurrency tests. - One commit per subsystem batch.
- JetStream sentinel tests run during Phase A as early-warning canaries.
3. Phase A: Foundation (~440 tests)
A1: Client Tests (79 missing)
Go file: client_test.go (82 tests)
Current .NET: ClientTests.cs (3 tests)
Categories to fill:
- Basic pub/sub (8): ClientSimplePubSub, PubSubNoEcho, PubWithQueueSub, PubSubWithReply
- Header handling (12): HeaderDeliverMsg, HeaderStrippedMsg, SliceHeader, SetHeaderOrdering
- UNSUB & auto-unsub (5): ClientUnSub, UnSubMax, AutoUnsubExactReceived
- Slow consumer (5): NoClientLeakOnSlowConsumer, MaxPending, FlushOutbound
- TLS connection (8): CloseTLSConnection, TLSHandshakeFirst, TLSFallbackDelay
- Auth & permissions (6): AuthTimeout, ResponsePermissions, QueueSubscribePermissions
- Client lifecycle (8): RemoveSubsOnDisconnect, MapRemoval, ConnectionName, Limits
- Message tracing (5): TraceMsg, TraceMsgHeaders, TraceMsgDelivery
- Protocol edge cases (10): ConnectProto, TypeString, SplitSubjectQueue, IPv6Address
- Miscellaneous (12): PingNotSentTooSoon, GWReplyPrefix, ReadloopWarning
New test files:
ClientPubSubTests.cs— basic messagingClientHeaderTests.cs— HPUB/HMSG handlingClientLifecycleTests.cs— connect/disconnect/cleanupClientSlowConsumerTests.cs— backpressureClientTlsTests.cs— TLS scenarios
A2: Parser Tests (9 missing)
Go file: parser_test.go (17 tests)
Current .NET: ParserTests.cs (8 tests)
Missing: ParsePubSizeOverflow, ParsePubArg, ParsePubBadSize, ParseHeaderPubArg, ParseRoutedHeaderMsg, ParseRouteMsg, ParseMsgSpace, ShouldFail (parametrized negatives), MaxControlLine.
Add to existing ParserTests.cs.
A3: SubList Tests (40 missing)
Go file: sublist_test.go (62 tests)
Current .NET: SubListTests.cs + SubjectMatchTests.cs (22 tests)
Categories:
- No-cache variants (~16): Add as
[Theory]data rows - Concurrency/race (3): RaceOnRemove, RaceOnInsert, RaceOnMatch — use
Task.WhenAll - Validation (6): InvalidSubjectsInsert, ValidLiteralSubjects
- Edge cases (8): LargeSubs, EmptyTokens, WildcardsAsLiterals
- Remote subs (2): RemoteQueueSubscriptions
- Utilities (5): SubjectCollide, SubjectToken, IsSubsetMatch
A4: Server Tests (27 missing)
Go file: server_test.go (44 tests)
Current .NET: ServerTests.cs + related (17 tests)
Major gaps: TLS version/cipher config (5), advertise URLs (3), max subscriptions (1), lame duck info (1), startup/shutdown edge cases (6), config validation (5), misc (6).
A5: Routes (58 missing)
Go file: routes_test.go (70 tests)
Current .NET: Route*Tests.cs (12 tests)
Major gaps: Route config/TLS (10), auth over routes (5), compression variants (15), per-account routing (5), pool management (5), slow consumer/reconnect (8), race conditions (5), misc (5).
A6: Gateways (79 missing)
Go file: gateway_test.go (88 tests)
Current .NET: Gateway*Tests.cs (9 tests)
Major gaps: Basic gateway flow (5), auth/TLS (8), service imports/exports (10), queue handling (8), interest tracking (10), reply mapping (5), URL discovery (5), compression (5), error handling (10), misc (13).
A7: Leaf Nodes (102 missing)
Go file: leafnode_test.go (110 tests)
Current .NET: Leaf*Tests.cs (8 tests)
Major gaps: Auth (10), TLS (8), loop detection (8), permissions (5), queue distribution (8), compression (5), WebSocket (15), import/export (10), topology (10), slow consumer (3), misc (20).
A8: Accounts (46 missing)
Go file: accounts_test.go (64 tests)
Current .NET: Account*Tests.cs (18 tests)
Major gaps: Config parsing (8), import/export (12), subject mapping (6), connection limits (4), service exports (5), latency tracking (3), misc (8).
4. Phase B: Distributed Substrate (~594 tests)
B1: RAFT Consensus (89 missing)
Go file: raft_test.go (104 tests)
Current .NET: Raft*Tests.cs (15 tests)
Categories: Election mechanics (15), log replication (20), snapshot (15), membership changes (10), partition handling (10), edge cases (19).
Write .NET-native scenario tests — RAFT timing behavior differs between goroutines and async/await. Focus on state-machine correctness invariants.
B2: Storage (267 missing)
Go files: filestore_test.go (232), memstore_test.go (37)
Current .NET: 2 tests
Build a storage contract suite + fault-injection harness:
- Contract tests: append/read/delete, compaction, retention/TTL, index rebuild, checksums, snapshot/recovery
- Failure tests: partial writes, fsync failures, restart during compaction, torn metadata, concurrent access
- Run same contracts against both
MemStoreandFileStoreviaIStreamStore - Focus on externally visible durability/invariants
Categories: FileStore basics (40), block management (30), retention/limits (25), recovery (35), compression (15), encryption (15), subject indexing (20), MemStore (35), snapshot/restore (15), failure injection (20), performance (17).
B3: Config & Reload (82 missing)
Go files: opts_test.go (86), reload_test.go (73)
Current .NET: Config*Tests.cs (77 tests)
Categories: CLI arg parsing (10), config file features (15), subsystem config (15), TLS config (10), auth config (8), hot reload (15), validation (9).
B4: Monitoring & Events (156 missing)
Go files: monitor_test.go (100), events_test.go (51), msgtrace_test.go (33)
Current .NET: MonitorTests.cs + EventTests.cs (28 tests)
Categories: /varz (20), /connz (25), /routez+/gatewayz+/leafz (20), /jsz (15), /healthz (5), system events (30), message tracing (25), signal handling (10), rate-limit logging (6).
5. Phase C: JetStream Depth (~889 tests)
C1: JetStream Core (390 missing)
Go files: jetstream_test.go (312), jetstream_consumer_test.go (160)
Current .NET: JetStream*Tests.cs (82 tests)
Categories: Stream lifecycle (40), publish semantics (30), consumer delivery (50), ack policies (25), retention policies (20), flow control (15), ordered consumers (10), subject transforms (15), mirror/source (25), API endpoints (30), account/permission (20), error handling (20), batching (15), direct API (10), misc (65).
C2: JetStream Clustering (499 missing)
Go files: jetstream_cluster_[1-4]_test.go (456), jetstream_super_cluster_test.go (47)
Current .NET: 4 tests
Write .NET-native cluster tests using in-process multi-server fixtures. Don't attempt 1:1 Go test translation — cover same behavioral contracts.
Categories: Cluster formation (30), multi-replica streams (50), consumer replication (40), leader failover (30), snapshot/catchup (25), super-cluster (45), mirror/source in cluster (30), account isolation (20), stream recovery (30), consumer edge cases (30), scaling (20), config reload (15), integration (134).
6. Phase D: Protocol Surfaces (~135 tests)
D1: MQTT (115 missing)
Go file: mqtt_test.go (123 tests)
Current .NET: Mqtt*Tests.cs (8 tests)
Categories: Packet parsing (15), QoS handling (20), session management (15), auth/TLS (10), keep-alive (5), topic handling (15), will messages (5), retain (5), integration (25).
D2: Auth/JWT Hardening (~20 missing)
JWT at 69% — fill claim validation edge cases, token rotation, revocation.
7. Completion Gates
Per-Phase Gates
- Phase A:
dotnet testpasses. Client pub/sub, routing, gateway, leaf node basics verified. - Phase B: RAFT election/append/snapshot pass. FileStore append/read/recovery pass. Monitor endpoints return valid JSON.
- Phase C: All JetStream API endpoints work. Stream/consumer lifecycle correct. Cluster failover preserves data.
- Phase D: MQTT pub/sub works. JWT full claim validation passes.
Final Gate
- Every Go test intent mapped in
go-dotnet-test-mapping.md dotnet testpasses with zero failures- No subsystem below 60% behavioral coverage
differences.mdsynchronized with verified behavior
8. Error Handling and Testing Strategy
- Preserve protocol-specific error semantics (NATS, MQTT, JetStream)
- Fail closed on account/auth/consensus violations
- Test-first for every capability
- Happy-path + edge/failure coverage per capability
- Integration tests for inter-server, RAFT/cluster, and restart durability
- Unit tests for deterministic parser/state primitives
- Use Shouldly assertions, xUnit 3, NSubstitute — never Assert.*, FluentAssertions, or Moq