Skip to content

test: Split unit, integration, and e2e tiers with just recipes - #55

Merged
korya merged 3 commits into
masterfrom
korya-chore-justfile-test-recipes
Sep 11, 2026
Merged

korya merged 3 commits into
masterfrom
korya-chore-justfile-test-recipes

Conversation

@korya

@korya korya commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Why

A developer iterating on a unit change waited about 150 seconds for go test ./..., because every tier ran in one pass and -short skipped only the soak. There was also no single command for the suite, the end-to-end subset, or a real measurement, and a bare just printed an error instead of a menu.

What & how

Split the tests into three tiers selected by -short and a build tag, and add just recipes for each plus real measurements.

Command Runs Wall time (root package)
just test -short unit only: nothing starts a listener or a process ~0.6 s
just test unit + integration (in-process nqserver, spawned binaries) ~150 s
just test-e2e only the tests in files tagged //go:build e2e ~5 s
go test -tags e2e ./... everything, as CI runs it ~160 s with -race
just measure-cloudflare, just measure-apple a real measurement with the nq CLI network-bound

Definition of unit. No I/O with anything external to the test. An in-process nqserver over loopback, a spawned nq binary, and nqserver bound to a port all count as external. Every site that starts one calls skipIfShort: inside the shared server-starting helper where one exists (five of them), at the top of the test otherwise. The soak already skipped under -short.

Why a build tag needs more than two lines. The two e2e_test.go files defined helpers that other tests use, so those helpers move to untagged helpers_test.go files or the plain build breaks. And a tag hides files from every tool that is not told about it, so CI, the release workflow, vet, and golangci-lint now pass -tags e2e. The lint job already carried the same warning for windows-tagged files.

Why test-e2e still filters by name. -tags e2e adds files to a package, it does not select them, so go test -tags e2e would run every tier. The recipe discovers files carrying the tag and runs only the tests they declare. Moving the e2e tests to their own package would be cleaner, but both files depend on package internals (package netquality, and the CLI's unexported entry point).

Out of scope: the root e2e_test.go runs full measurements against an in-process server, much like run_test.go, so its "e2e" label is loose. It keeps the tag as-is to limit churn; reclassifying it is a separate decision.

No public responsiveness servers exist beyond Apple and Cloudflare. Self-hosted servers remain reachable through nq --well-known or --config-url.

Other changes

  • The README testing section and the AGENTS.md build/test row document the three modes and the tag.
  • The justfile is formatted with just --fmt, and a bare just lists the recipes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01B4xBvbUJ5Ci1b99X5x8LJL

korya and others added 3 commits September 11, 2026 11:26
Previously, the justfile only had benchmark recipes and running the suite, the e2e subset, or a
real measurement meant remembering the right `go test`/`go run` incantation. Now, `just test`,
`just test-e2e`, `just measure-cloudflare`, and `just measure-apple` cover those, and the bare
`just` lists the recipes.

`test-e2e` derives its `-run` regex from the `Test*` functions in the `e2e_test.go` files at run
time rather than introducing a build tag, so `go test ./...` and CI keep running the e2e tests
unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4xBvbUJ5Ci1b99X5x8LJL
Previously, `go test ./...` ran every tier in one pass and `-short` skipped only the soak, so a
unit-level iteration cost about 150 s. Now the two `e2e_test.go` files carry `//go:build e2e`,
and every test that starts a listener or a process calls `skipIfShort`, so `go test -short
./...` finishes in about a second per package.

"Unit" here means no I/O with anything external to the test: an in-process nqserver over
loopback, a spawned `nq` binary, and `nqserver` bound to a port all count as external. The
guard lives in the shared server-starting helpers where one exists and at the top of the
test otherwise.

The helpers the e2e files shared with other tests move to untagged `helpers_test.go` files so
the plain build still compiles. CI, the release workflow, vet, and golangci-lint pass
`-tags e2e` so the tagged files stay tested and linted; without that they would silently
drop out of both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4xBvbUJ5Ci1b99X5x8LJL
Previously, `test-e2e` grepped test names out of two hard-coded file names and `test` ran the
e2e tests too. Now `test` runs unit and integration tests only, `test -short` unit only, and
`test-e2e` discovers every file tagged `//go:build e2e` and runs just the tests it declares,
under the tag. The README testing section documents the three modes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4xBvbUJ5Ci1b99X5x8LJL
@korya korya changed the title chore(justfile): Add test, test-e2e, and measure-* recipes test: Split unit, integration, and e2e tiers with just recipes Sep 11, 2026
@korya
korya marked this pull request as ready for review September 11, 2026 16:06
@korya
korya merged commit eb13f5b into master Sep 11, 2026
13 checks passed
@korya
korya deleted the korya-chore-justfile-test-recipes branch September 11, 2026 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant