Make the end-to-end suite opt-in and a separate CI step - #58
Merged
Merged
Conversation
The suite ran three times per CI job -- once each under test, test-race and test-cover -- for about 32s of the runtime. Now it runs once, in a CI step of its own, and `go test ./...` no longer pays for it at all. Previously every test recipe pulled in the end-to-end runs. Now they are gated behind a registered -e2e flag and skipped by default, so `just test` is a 0.5s unit loop and `just test-e2e` is the explicit 10s gate. `just pre-push` runs both for anyone who wants the CI contract locally. The gate is a flag rather than a build tag deliberately. A //go:build-tagged file is invisible to `go vet` and `golangci-lint` unless every invocation passes the tag: a file carrying both a Printf arg mismatch and dead code passes each tool clean when tagged, and only fails under -tags. Tagging would therefore drop 1100 lines of test code out of both linters, silently. The flag keeps every file compiled and analysed while giving the same opt-in default. Placing the check inside binary() rather than in each test means an end-to-end test added later inherits it automatically; there is no per-file marker to forget. Coverage is unaffected -- test-cover opts into -e2e itself and still reports 99.3%. One consequence worth naming: `just pre-commit` no longer exercises the end-to-end suite, so a break there surfaces in CI rather than before the commit. `just pre-push` exists for anyone who prefers to find out earlier. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019EMMhgmTkbzAsmeNy97PrP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The end-to-end suite ran three times per CI job — about 32s of the runtime — and slowed
go test ./...from 0.5s to 11s for everyone.pre-commitchainstest,test-raceandtest-cover, and each pulled in the full suite. Two of those runs bought almost nothing:testandtest-coverare near-duplicates.test-coverruns the identical tests and additionally reports coverage.test-racewas checking the wrong process.-raceinstruments the test binary, but the harness builds the CLI with a separate plaingo build, so the race detector covered the harness and thehttptestservers — not one line ofhttp-assert. (A race build is 12.1 MB vs 9.9 MB plain; the child is the plain one.)The redundancy predates the suite —
pre-commitalways ran three test passes. Adding e2e just turned a latent waste into a visible one.Solution
Gate the suite behind an opt-in
-e2eflag and give it a CI step of its own, so it runs exactly once.CI e2e time: ~32s → ~10s, and a failure now names itself instead of hiding inside a composite recipe.
Why a flag and not a build tag
A
//go:build e2efile is invisible togo vetandgolangci-lintunless every invocation passes the tag. Tested on a file carrying both aPrintfargument mismatch and dead code:go vet ./...golangci-lint run ./...0 issues.go vet -tags=e2e ./...Printfbuggolangci-lint run --build-tags=e2e ./...2 issues: govet 1, unused 1Tagging would drop 1,100 lines of test code out of both linters, silently, because the recipes are plain
go vet ./...andgolangci-lint run ./.... A registered flag gives the same opt-in default with every file still compiled and analysed.Why the check lives in
binary()Putting it in the one function every e2e test already routes through means a test added later inherits the gate automatically. There is no per-file marker to forget, and no way to write an e2e test that quietly runs in the fast loop.
Coverage is unaffected:
test-coveropts into-e2eitself and still reports 99.3%.Other Changes
Adds
just pre-push(pre-commit+test-e2e) — the full CI contract in one local command.One consequence worth naming:
just pre-commitno longer exercises the suite, so a break there surfaces in CI rather than before the commit. That is the intended trade — a fast inner loop, withpre-pushavailable for anyone who wants to find out earlier.Related:
🤖 Generated with Claude Code