This project uses tests to freeze compatibility behavior, not just to catch accidental regressions.
- Protocol behavior is part of the public contract.
- Every code change starts with a failing test.
- Tests should describe externally visible behavior whenever possible.
- Captured fixtures and golden data must be owned by this project.
- Manual testing complements the suite; it never replaces it.
Use golden tests when the exact bytes matter.
Typical use cases:
- frame envelope encoding and decoding
- control packets
- login and selection packets
- main-character bootstrap packets
- movement packets
- inventory/equipment bootstrap packets frozen by
internal/proto/itemgolden tests
Golden tests answer:
- “does this packet match the expected wire format exactly?”
Store project-owned fixtures under package-local testdata/ directories unless a shared cross-package fixture set is explicitly needed.
Current protocol fixtures live beside their codec packages (for example internal/proto/item/testdata/).
Use unit tests for:
- frame parsers
- packet validators
- state transitions
- config loaders
- repositories and data mappers
- helper functions used by the protocol layer
Unit tests should be fast and deterministic.
Use E2E tests for behaviors that only make sense across the wire:
- connect
- handshake
- login
- character list
- create character
- select character
- enter game
- move
E2E tests answer:
- “does the server behave correctly as a networked system?”
The preferred test harness is a small Go test client that:
- opens a TCP connection
- writes raw frames or packet structs
- reads responses
- asserts bytes, fields, and phase transitions
Use fuzzing for:
- frame decoding
- packet decoding
- boundary checking
- malformed lengths
- truncated payloads
Fuzzing helps harden the server against malformed or hostile input early.
Manual validation is still required for milestone closures, especially when a real client is involved.
Manual validation should confirm:
- the target client connects
- the visible phase flow is correct
- the client does not hang or disconnect unexpectedly
pprofand logs remain usable when the server is under interaction
The reusable manual checklist for current real-client coverage lives at:
docs/qa/manual-client-checklist.md
Manual validation must be documented in commit messages, issue notes, or follow-up docs when it proves something important.
For code changes, the workflow is:
- add or refine the spec
- write the failing test
- run the test and confirm it fails for the expected reason
- implement the minimum code required
- run the test again
- run the broader suite
No production code should be added without a failing test first.
Base suite:
go test ./...Target a single package or pattern:
go test ./internal/ops
go test ./... -run TestNameFuzzing example:
go test ./... -fuzz=Fuzz -run=^$Coverage example:
go test ./... -coverFixtures in this repository must be project-owned artifacts.
Allowed fixture sources:
- packet captures produced in the lab
- byte sequences rewritten into project-owned files
- fixtures derived from current observed behavior and rewritten here in our own format
Not allowed:
- vendoring external client or server source trees into this repo
- pasting large legacy code fragments as “test helpers”
- storing proprietary assets that are not required for protocol validation
The first wave of protocol work should add tests in this order:
- frame decoder golden tests
- frame encoder golden tests
- session phase transition tests
- handshake E2E tests
- login/auth E2E tests
- character list E2E tests
- create character E2E tests
- select character E2E tests
- enter game E2E tests
- movement E2E tests
Use:
dlvfor stepping through handlers and decoderspproffor memory, goroutine, blocking, and mutex analysis- structured logs for packet-level debugging
If a test failure requires a long manual debugging session, add a regression test before changing the code.
Documentation-only changes do not need a failing automated test, but they still need validation:
- the document must match current repo reality
- commands must be runnable or clearly marked as future work
- links and file paths must exist after the change