Server timeout tests protect the constructor but not the call site, and carry an inverted rationale comment #120
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Non-blocking findings from the review of PR #118, collected here rather than spent on another review cycle. The timeout values themselves are correct and thoroughly verified — nothing here questions them.
Applies to
internal/server/server.goandinternal/server/server_test.goas they exist after #118 merges.1. The regression test does not cover the regression it was written for
#99's definition of done, item 4, asked for a test asserting all four timeout fields are non-zero "so a future refactor cannot silently drop one."
The tests deliver half of that. All four call
newHTTPServer(...)directly and assert on its output. Nothing asserts thatRun()actually usesnewHTTPServer. A refactor that revertsinternal/server/server.go:145to an inline&http.Server{Addr: ..., Handler: ...}— dropping every timeout — would leave the entire suite green, because the tests would still be exercising a constructor the running server no longer calls.The protection is on the constructor; the risk is at the call site. This is a partial miss of the original contract, recorded rather than waved through.
2. The rationale comment is backwards
internal/server/server_test.go:83explains theReadTimeout>=ReadHeaderTimeoutinvariant by claiming a smallerReadTimeout"would makeReadHeaderTimeoutunreachable."That is not what happens. Verified against the pinned toolchain (go1.25.7, resolved from the
Dockerfiledigest):readHeaderTimeout()returnss.ReadHeaderTimeoutwhenever it is non-zero and applies it directly, so the header phase keeps its full 10s regardless ofReadTimeout. What actually breaks is the whole-request deadline —if !hdrDeadline.Equal(wholeReqDeadline) { c.rwc.SetReadDeadline(wholeReqDeadline) }installs a deadline that has already expired.The asserted invariant is correct. Only the explanation is wrong. That is precisely what makes it worth fixing: a confidently stated, incorrect account of subtle stdlib deadline semantics is what a future maintainer will reason from when deciding whether a change is safe.
The same wording appears in three places and all three need correcting: the test comment, the body of PR #118, and the plan comment on #99.
3.
TestHTTPServerAddrAndHandleris near-tautologicalIt asserts that a two-field struct literal copies its two arguments. It cannot realistically fail. Either strengthen it into something that could, or drop it — a test that cannot fail is a maintenance cost that pays no rent.
Definition of done
Run()carries the timeouts — i.e. the wiring, not just the constructor. Whatever shape you choose, it must fail ifRun()is changed to build itshttp.Serverinline without timeouts. That failure mode is the entire point; do not write something that merely re-asserts the constructor from a different angle.ReadTimeoutinstalls an already-expired whole-request deadline. Do not overcorrect into a new wrong claim — check it against the pinned toolchain in theDockerfile, not whatever Go is on your machine, and cite what you read.TestHTTPServerAddrAndHandlereither strengthened or removed, with the choice justified in the PR description.Run()to an inline&http.Server{...}without timeouts, confirm the new test fails, revert, confirmgit statusis clean andmake checkis green. Report what you mutated and the exact failure it produced. A code-reading argument is not sufficient — the whole finding is that the existing tests look like they cover this and do not.make checkgreen;TODO.mdupdated in the same commit.The finishing commit's title must end with
(closes #N)referencing this issue.Scope
Do not change any timeout value.
ReadHeaderTimeout10s,ReadTimeout15s,WriteTimeout75s,IdleTimeout120s were each reasoned about and independently verified in #118 — including confirmation thatReadTimeout15s does not sever a 60s handler, becausestartBackgroundReadclears the read deadline before dispatch on bodyless requests. If you believe a value is wrong, say so in the PR description with evidence; do not quietly adjust one.Do not touch
routes.go,internal/middleware,internal/watcher, orinternal/resolver.Sequencing
Blocked until PR #118 merges — every line referenced here only exists on that branch.
Hard constraints
.golangci.yml(sha256021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb); do not change the golangci-lint pin.maketargets andscript/entrypoints only — no directgo test/go build/go clean/golangci-lint.script/cibuildcan report a false green on an unchanged tree (#115). Force a real build and use a negative control.