Files
natsdotnet/docs/plans/2026-02-23-go-dotnet-test-parity-design.md
Joseph Doherty f6fab376ad docs: add go-to-dotnet systematic test parity design
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).
2026-02-23 17:24:57 -05:00

236 lines
11 KiB
Markdown

# 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:
1. **Phase A (Foundation):** Client, Parser, SubList, Server, Routes, Gateways, Leaf Nodes, Accounts (~440 tests)
2. **Phase B (Distributed Substrate):** RAFT, Storage, Config/Reload, Monitoring/Events (~594 tests)
3. **Phase C (JetStream Depth):** JetStream Core, JetStream Clustering (~889 tests)
4. **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.md` tracking 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 test` before 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 messaging
- `ClientHeaderTests.cs` — HPUB/HMSG handling
- `ClientLifecycleTests.cs` — connect/disconnect/cleanup
- `ClientSlowConsumerTests.cs` — backpressure
- `ClientTlsTests.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 `MemStore` and `FileStore` via `IStreamStore`
- 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:** Monitor*Tests.cs + Event*Tests.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 test` passes. 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 test` passes with zero failures
- No subsystem below 60% behavioral coverage
- `differences.md` synchronized 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