From f6fab376ad685b3d5a94c1baa8ecfdf4e61241dd Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 23 Feb 2026 17:24:57 -0500 Subject: [PATCH] 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-go-dotnet-test-parity-design.md | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 docs/plans/2026-02-23-go-dotnet-test-parity-design.md diff --git a/docs/plans/2026-02-23-go-dotnet-test-parity-design.md b/docs/plans/2026-02-23-go-dotnet-test-parity-design.md new file mode 100644 index 0000000..30c1b96 --- /dev/null +++ b/docs/plans/2026-02-23-go-dotnet-test-parity-design.md @@ -0,0 +1,235 @@ +# 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